]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/util.c
shared: procfs_file_alloca: handle pid==0
[thirdparty/systemd.git] / src / shared / util.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
60918275 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 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
a7334b09
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.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
60918275
LP
22#include <assert.h>
23#include <string.h>
24#include <unistd.h>
25#include <errno.h>
85261803 26#include <stdlib.h>
034c6ed7
LP
27#include <signal.h>
28#include <stdio.h>
1dccbe19
LP
29#include <syslog.h>
30#include <sched.h>
31#include <sys/resource.h>
ef886c6a 32#include <linux/sched.h>
a9f5d454
LP
33#include <sys/types.h>
34#include <sys/stat.h>
3a0ecb08 35#include <fcntl.h>
a0d40ac5 36#include <dirent.h>
601f6a1e
LP
37#include <sys/ioctl.h>
38#include <linux/vt.h>
39#include <linux/tiocl.h>
80876c20
LP
40#include <termios.h>
41#include <stdarg.h>
42#include <sys/inotify.h>
43#include <sys/poll.h>
3177a7fa 44#include <ctype.h>
5b6319dc 45#include <sys/prctl.h>
ef2f1067
LP
46#include <sys/utsname.h>
47#include <pwd.h>
4fd5948e 48#include <netinet/ip.h>
3fe5e5d4 49#include <linux/kd.h>
afea26ad 50#include <dlfcn.h>
2e78aa99 51#include <sys/wait.h>
7948c4df 52#include <sys/time.h>
8092a428 53#include <glob.h>
4b67834e 54#include <grp.h>
87d2c1ff 55#include <sys/mman.h>
825c6fe5
LP
56#include <sys/vfs.h>
57#include <linux/magic.h>
0b507b17 58#include <limits.h>
09017585
MS
59#include <langinfo.h>
60#include <locale.h>
844ec79b 61#include <libgen.h>
2b6bf07d 62#undef basename
60918275 63
9bf3b535
LP
64#ifdef HAVE_SYS_AUXV_H
65#include <sys/auxv.h>
66#endif
67
60918275
LP
68#include "macro.h"
69#include "util.h"
1dccbe19
LP
70#include "ioprio.h"
71#include "missing.h"
a9f5d454 72#include "log.h"
65d2ebdc 73#include "strv.h"
e51bc1a2 74#include "label.h"
9eb977db 75#include "path-util.h"
d06dacd0 76#include "exit-status.h"
83cc030f 77#include "hashmap.h"
4d1a6904 78#include "env-util.h"
a5c32cff 79#include "fileio.h"
8f6ce71f 80#include "device-nodes.h"
f405e86d
SL
81#include "utf8.h"
82#include "gunicode.h"
295edddf 83#include "virt.h"
477def80 84#include "def.h"
56cf987f 85
9a0e6896
LP
86int saved_argc = 0;
87char **saved_argv = NULL;
9086e840 88
28917d7d 89static volatile unsigned cached_columns = 0;
ed757c0c 90static volatile unsigned cached_lines = 0;
9a0e6896 91
37f85e66 92size_t page_size(void) {
ec202eae 93 static thread_local size_t pgsz = 0;
37f85e66 94 long r;
95
87d2c1ff 96 if (_likely_(pgsz > 0))
37f85e66 97 return pgsz;
98
e67f47e5
LP
99 r = sysconf(_SC_PAGESIZE);
100 assert(r > 0);
37f85e66 101
102 pgsz = (size_t) r;
37f85e66 103 return pgsz;
104}
105
e05797fb
LP
106bool streq_ptr(const char *a, const char *b) {
107
108 /* Like streq(), but tries to make sense of NULL pointers */
109
110 if (a && b)
111 return streq(a, b);
112
113 if (!a && !b)
114 return true;
115
116 return false;
117}
118
8c7c140f 119char* endswith(const char *s, const char *postfix) {
60918275
LP
120 size_t sl, pl;
121
122 assert(s);
123 assert(postfix);
124
125 sl = strlen(s);
126 pl = strlen(postfix);
127
d4d0d4db 128 if (pl == 0)
8c7c140f 129 return (char*) s + sl;
d4d0d4db 130
60918275 131 if (sl < pl)
8c7c140f
LP
132 return NULL;
133
134 if (memcmp(s + sl - pl, postfix, pl) != 0)
135 return NULL;
60918275 136
8c7c140f 137 return (char*) s + sl - pl;
60918275
LP
138}
139
79d6d816
LP
140bool first_word(const char *s, const char *word) {
141 size_t sl, wl;
142
143 assert(s);
144 assert(word);
145
146 sl = strlen(s);
147 wl = strlen(word);
148
149 if (sl < wl)
150 return false;
151
d4d0d4db
LP
152 if (wl == 0)
153 return true;
154
79d6d816
LP
155 if (memcmp(s, word, wl) != 0)
156 return false;
157
d4d0d4db
LP
158 return s[wl] == 0 ||
159 strchr(WHITESPACE, s[wl]);
79d6d816
LP
160}
161
42f4e3c4 162int close_nointr(int fd) {
b0ee8068 163 int r;
60918275 164
b0ee8068
CW
165 assert(fd >= 0);
166 r = close(fd);
167
168 /* Just ignore EINTR; a retry loop is the wrong
169 * thing to do on Linux.
170 *
171 * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
172 * https://bugzilla.gnome.org/show_bug.cgi?id=682819
173 * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR
174 * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain
175 */
176 if (_unlikely_(r < 0 && errno == EINTR))
177 return 0;
178 else if (r >= 0)
179 return r;
180 else
181 return -errno;
60918275 182}
85261803 183
85f136b5 184void close_nointr_nofail(int fd) {
5c0aa72a 185 PROTECT_ERRNO;
85f136b5
LP
186
187 /* like close_nointr() but cannot fail, and guarantees errno
188 * is unchanged */
189
190 assert_se(close_nointr(fd) == 0);
191}
192
5b6319dc
LP
193void close_many(const int fds[], unsigned n_fd) {
194 unsigned i;
195
2c93b4ef
LP
196 assert(fds || n_fd <= 0);
197
5b6319dc
LP
198 for (i = 0; i < n_fd; i++)
199 close_nointr_nofail(fds[i]);
200}
201
4b73a0c0
LP
202int unlink_noerrno(const char *path) {
203 PROTECT_ERRNO;
204 int r;
205
206 r = unlink(path);
207 if (r < 0)
208 return -errno;
209
210 return 0;
211}
212
85261803
LP
213int parse_boolean(const char *v) {
214 assert(v);
215
b43d1d01 216 if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || strcaseeq(v, "on"))
85261803 217 return 1;
b43d1d01 218 else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || strcaseeq(v, "off"))
85261803
LP
219 return 0;
220
221 return -EINVAL;
222}
223
3ba686c1 224int parse_pid(const char *s, pid_t* ret_pid) {
0b172489 225 unsigned long ul = 0;
3ba686c1
LP
226 pid_t pid;
227 int r;
228
229 assert(s);
230 assert(ret_pid);
231
e67f47e5
LP
232 r = safe_atolu(s, &ul);
233 if (r < 0)
3ba686c1
LP
234 return r;
235
236 pid = (pid_t) ul;
237
238 if ((unsigned long) pid != ul)
239 return -ERANGE;
240
241 if (pid <= 0)
242 return -ERANGE;
243
244 *ret_pid = pid;
245 return 0;
246}
247
034a2a52
LP
248int parse_uid(const char *s, uid_t* ret_uid) {
249 unsigned long ul = 0;
250 uid_t uid;
251 int r;
252
253 assert(s);
254 assert(ret_uid);
255
e67f47e5
LP
256 r = safe_atolu(s, &ul);
257 if (r < 0)
034a2a52
LP
258 return r;
259
260 uid = (uid_t) ul;
261
262 if ((unsigned long) uid != ul)
263 return -ERANGE;
264
265 *ret_uid = uid;
266 return 0;
267}
268
85261803
LP
269int safe_atou(const char *s, unsigned *ret_u) {
270 char *x = NULL;
034c6ed7 271 unsigned long l;
85261803
LP
272
273 assert(s);
274 assert(ret_u);
275
276 errno = 0;
277 l = strtoul(s, &x, 0);
278
f3910003 279 if (!x || x == s || *x || errno)
48deb058 280 return errno > 0 ? -errno : -EINVAL;
85261803 281
034c6ed7 282 if ((unsigned long) (unsigned) l != l)
85261803
LP
283 return -ERANGE;
284
285 *ret_u = (unsigned) l;
286 return 0;
287}
288
289int safe_atoi(const char *s, int *ret_i) {
290 char *x = NULL;
034c6ed7 291 long l;
85261803
LP
292
293 assert(s);
294 assert(ret_i);
295
296 errno = 0;
297 l = strtol(s, &x, 0);
298
f3910003 299 if (!x || x == s || *x || errno)
48deb058 300 return errno > 0 ? -errno : -EINVAL;
85261803 301
034c6ed7 302 if ((long) (int) l != l)
85261803
LP
303 return -ERANGE;
304
034c6ed7
LP
305 *ret_i = (int) l;
306 return 0;
307}
308
034c6ed7
LP
309int safe_atollu(const char *s, long long unsigned *ret_llu) {
310 char *x = NULL;
311 unsigned long long l;
312
313 assert(s);
314 assert(ret_llu);
315
316 errno = 0;
317 l = strtoull(s, &x, 0);
318
f3910003 319 if (!x || x == s || *x || errno)
034c6ed7
LP
320 return errno ? -errno : -EINVAL;
321
322 *ret_llu = l;
323 return 0;
324}
325
326int safe_atolli(const char *s, long long int *ret_lli) {
327 char *x = NULL;
328 long long l;
329
330 assert(s);
331 assert(ret_lli);
332
333 errno = 0;
334 l = strtoll(s, &x, 0);
335
f3910003 336 if (!x || x == s || *x || errno)
034c6ed7
LP
337 return errno ? -errno : -EINVAL;
338
339 *ret_lli = l;
85261803
LP
340 return 0;
341}
a41e8209 342
f7900e25
TA
343int safe_atod(const char *s, double *ret_d) {
344 char *x = NULL;
32b2634e 345 double d = 0;
f7900e25
TA
346
347 assert(s);
348 assert(ret_d);
349
d6dd604b
LP
350 RUN_WITH_LOCALE(LC_NUMERIC_MASK, "C") {
351 errno = 0;
352 d = strtod(s, &x);
353 }
f7900e25
TA
354
355 if (!x || x == s || *x || errno)
356 return errno ? -errno : -EINVAL;
357
358 *ret_d = (double) d;
359 return 0;
360}
361
a41e8209 362/* Split a string into words. */
65d2ebdc 363char *split(const char *c, size_t *l, const char *separator, char **state) {
a41e8209
LP
364 char *current;
365
366 current = *state ? *state : (char*) c;
367
368 if (!*current || *c == 0)
369 return NULL;
370
65d2ebdc
LP
371 current += strspn(current, separator);
372 *l = strcspn(current, separator);
82919e3d
LP
373 *state = current+*l;
374
375 return (char*) current;
376}
377
034c6ed7
LP
378/* Split a string into words, but consider strings enclosed in '' and
379 * "" as words even if they include spaces. */
380char *split_quoted(const char *c, size_t *l, char **state) {
70f75a52 381 const char *current, *e;
0bab36f2 382 bool escaped = false;
034c6ed7 383
70f75a52
LP
384 assert(c);
385 assert(l);
386 assert(state);
034c6ed7 387
70f75a52 388 current = *state ? *state : c;
034c6ed7
LP
389
390 current += strspn(current, WHITESPACE);
391
70f75a52
LP
392 if (*current == 0)
393 return NULL;
394
395 else if (*current == '\'') {
034c6ed7 396 current ++;
034c6ed7 397
0bab36f2
LP
398 for (e = current; *e; e++) {
399 if (escaped)
400 escaped = false;
401 else if (*e == '\\')
402 escaped = true;
403 else if (*e == '\'')
404 break;
405 }
406
407 *l = e-current;
70f75a52
LP
408 *state = (char*) (*e == 0 ? e : e+1);
409
034c6ed7
LP
410 } else if (*current == '\"') {
411 current ++;
034c6ed7 412
0bab36f2
LP
413 for (e = current; *e; e++) {
414 if (escaped)
415 escaped = false;
416 else if (*e == '\\')
417 escaped = true;
418 else if (*e == '\"')
419 break;
420 }
421
422 *l = e-current;
70f75a52
LP
423 *state = (char*) (*e == 0 ? e : e+1);
424
034c6ed7 425 } else {
0bab36f2
LP
426 for (e = current; *e; e++) {
427 if (escaped)
428 escaped = false;
429 else if (*e == '\\')
430 escaped = true;
431 else if (strchr(WHITESPACE, *e))
432 break;
433 }
434 *l = e-current;
70f75a52 435 *state = (char*) e;
034c6ed7
LP
436 }
437
5b12334d 438 return (char*) current;
034c6ed7
LP
439}
440
034c6ed7
LP
441int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
442 int r;
2fbe635a 443 _cleanup_fclose_ FILE *f = NULL;
49aa47c7 444 char line[LINE_MAX];
bb00e604 445 long unsigned ppid;
49aa47c7 446 const char *p;
034c6ed7 447
49aa47c7 448 assert(pid >= 0);
034c6ed7
LP
449 assert(_ppid);
450
49aa47c7
LP
451 if (pid == 0) {
452 *_ppid = getppid();
453 return 0;
454 }
034c6ed7 455
49aa47c7
LP
456 p = procfs_file_alloca(pid, "stat");
457 f = fopen(p, "re");
2fbe635a 458 if (!f)
034c6ed7
LP
459 return -errno;
460
2fbe635a 461 if (!fgets(line, sizeof(line), f)) {
35d50f55 462 r = feof(f) ? -EIO : -errno;
034c6ed7
LP
463 return r;
464 }
465
034c6ed7
LP
466 /* Let's skip the pid and comm fields. The latter is enclosed
467 * in () but does not escape any () in its value, so let's
468 * skip over it manually */
469
2fbe635a
LP
470 p = strrchr(line, ')');
471 if (!p)
034c6ed7
LP
472 return -EIO;
473
474 p++;
475
476 if (sscanf(p, " "
477 "%*c " /* state */
bb00e604 478 "%lu ", /* ppid */
034c6ed7
LP
479 &ppid) != 1)
480 return -EIO;
481
bb00e604 482 if ((long unsigned) (pid_t) ppid != ppid)
034c6ed7
LP
483 return -ERANGE;
484
485 *_ppid = (pid_t) ppid;
486
487 return 0;
488}
489
7640a5de 490int get_starttime_of_pid(pid_t pid, unsigned long long *st) {
e67f47e5 491 _cleanup_fclose_ FILE *f = NULL;
49aa47c7
LP
492 char line[LINE_MAX];
493 const char *p;
7640a5de 494
49aa47c7 495 assert(pid >= 0);
7640a5de
LP
496 assert(st);
497
b68fa010 498 p = procfs_file_alloca(pid, "stat");
7640a5de 499
49aa47c7 500 f = fopen(p, "re");
e67f47e5 501 if (!f)
5b12334d 502 return errno == ENOENT ? -ESRCH : -errno;
7640a5de 503
e67f47e5
LP
504 if (!fgets(line, sizeof(line), f)) {
505 if (ferror(f))
506 return -errno;
7640a5de 507
e67f47e5
LP
508 return -EIO;
509 }
7640a5de
LP
510
511 /* Let's skip the pid and comm fields. The latter is enclosed
512 * in () but does not escape any () in its value, so let's
513 * skip over it manually */
514
e67f47e5
LP
515 p = strrchr(line, ')');
516 if (!p)
7640a5de
LP
517 return -EIO;
518
519 p++;
520
521 if (sscanf(p, " "
522 "%*c " /* state */
523 "%*d " /* ppid */
524 "%*d " /* pgrp */
525 "%*d " /* session */
526 "%*d " /* tty_nr */
527 "%*d " /* tpgid */
528 "%*u " /* flags */
529 "%*u " /* minflt */
530 "%*u " /* cminflt */
531 "%*u " /* majflt */
532 "%*u " /* cmajflt */
533 "%*u " /* utime */
534 "%*u " /* stime */
535 "%*d " /* cutime */
536 "%*d " /* cstime */
537 "%*d " /* priority */
538 "%*d " /* nice */
539 "%*d " /* num_threads */
540 "%*d " /* itrealvalue */
541 "%llu " /* starttime */,
542 st) != 1)
543 return -EIO;
544
545 return 0;
546}
547
34ca941c
LP
548int fchmod_umask(int fd, mode_t m) {
549 mode_t u;
550 int r;
551
552 u = umask(0777);
553 r = fchmod(fd, m & (~u)) < 0 ? -errno : 0;
554 umask(u);
555
556 return r;
557}
558
7072ced8
LP
559char *truncate_nl(char *s) {
560 assert(s);
561
562 s[strcspn(s, NEWLINE)] = 0;
563 return s;
564}
565
87d2c1ff 566int get_process_comm(pid_t pid, char **name) {
49aa47c7 567 const char *p;
5b12334d 568 int r;
7072ced8 569
7072ced8 570 assert(name);
49aa47c7 571 assert(pid >= 0);
7072ced8 572
b68fa010 573 p = procfs_file_alloca(pid, "comm");
7072ced8 574
5b12334d
LP
575 r = read_one_line_file(p, name);
576 if (r == -ENOENT)
577 return -ESRCH;
578
579 return r;
7072ced8
LP
580}
581
87d2c1ff 582int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) {
49aa47c7 583 _cleanup_fclose_ FILE *f = NULL;
9bdbc2e2 584 char *r = NULL, *k;
49aa47c7 585 const char *p;
c59760ee 586 int c;
c59760ee 587
c59760ee 588 assert(line);
49aa47c7 589 assert(pid >= 0);
c59760ee 590
b68fa010 591 p = procfs_file_alloca(pid, "cmdline");
c59760ee 592
49aa47c7 593 f = fopen(p, "re");
c59760ee
LP
594 if (!f)
595 return -errno;
49aa47c7 596
9bdbc2e2 597 if (max_length == 0) {
49aa47c7
LP
598 size_t len = 0, allocated = 0;
599
9bdbc2e2 600 while ((c = getc(f)) != EOF) {
49aa47c7
LP
601
602 if (!GREEDY_REALLOC(r, allocated, len+2)) {
9bdbc2e2 603 free(r);
9bdbc2e2
LN
604 return -ENOMEM;
605 }
49aa47c7
LP
606
607 r[len++] = isprint(c) ? c : ' ';
9bdbc2e2 608 }
49aa47c7
LP
609
610 if (len > 0)
611 r[len-1] = 0;
612
9bdbc2e2
LN
613 } else {
614 bool space = false;
615 size_t left;
49aa47c7 616
9bdbc2e2 617 r = new(char, max_length);
49aa47c7 618 if (!r)
9bdbc2e2 619 return -ENOMEM;
c59760ee 620
9bdbc2e2
LN
621 k = r;
622 left = max_length;
623 while ((c = getc(f)) != EOF) {
c59760ee 624
9bdbc2e2
LN
625 if (isprint(c)) {
626 if (space) {
627 if (left <= 4)
628 break;
629
630 *(k++) = ' ';
631 left--;
632 space = false;
633 }
c59760ee 634
c59760ee
LP
635 if (left <= 4)
636 break;
637
9bdbc2e2 638 *(k++) = (char) c;
057fbb58 639 left--;
9bdbc2e2
LN
640 } else
641 space = true;
642 }
c59760ee 643
9bdbc2e2
LN
644 if (left <= 4) {
645 size_t n = MIN(left-1, 3U);
646 memcpy(k, "...", n);
647 k[n] = 0;
648 } else
649 *k = 0;
c59760ee
LP
650 }
651
35d2e7ec 652 /* Kernel threads have no argv[] */
9bdbc2e2 653 if (r == NULL || r[0] == 0) {
b47d419c 654 _cleanup_free_ char *t = NULL;
35d2e7ec
LP
655 int h;
656
657 free(r);
658
87d2c1ff
LP
659 if (!comm_fallback)
660 return -ENOENT;
661
662 h = get_process_comm(pid, &t);
663 if (h < 0)
35d2e7ec
LP
664 return h;
665
b7def684 666 r = strjoin("[", t, "]", NULL);
87d2c1ff 667 if (!r)
35d2e7ec
LP
668 return -ENOMEM;
669 }
fa776d8e 670
c59760ee
LP
671 *line = r;
672 return 0;
673}
674
1e5678d0 675int is_kernel_thread(pid_t pid) {
49aa47c7 676 const char *p;
1e5678d0
LP
677 size_t count;
678 char c;
679 bool eof;
680 FILE *f;
681
682 if (pid == 0)
683 return 0;
684
49aa47c7 685 assert(pid > 0);
1e5678d0 686
49aa47c7
LP
687 p = procfs_file_alloca(pid, "cmdline");
688 f = fopen(p, "re");
1e5678d0
LP
689 if (!f)
690 return -errno;
691
692 count = fread(&c, 1, 1, f);
693 eof = feof(f);
694 fclose(f);
695
696 /* Kernel threads have an empty cmdline */
697
698 if (count <= 0)
699 return eof ? 1 : -errno;
700
701 return 0;
702}
703
3a832116
SL
704int get_process_capeff(pid_t pid, char **capeff) {
705 const char *p;
3a832116
SL
706
707 assert(capeff);
708 assert(pid >= 0);
709
b68fa010 710 p = procfs_file_alloca(pid, "status");
3a832116 711
69ab8088 712 return get_status_field(p, "\nCapEff:", capeff);
3a832116 713}
49aa47c7 714
87d2c1ff 715int get_process_exe(pid_t pid, char **name) {
49aa47c7 716 const char *p;
e79f68d1
ZJS
717 char *d;
718 int r;
87d2c1ff 719
49aa47c7 720 assert(pid >= 0);
87d2c1ff
LP
721 assert(name);
722
b68fa010 723 p = procfs_file_alloca(pid, "exe");
87d2c1ff 724
e79f68d1
ZJS
725 r = readlink_malloc(p, name);
726 if (r < 0)
5b12334d 727 return r == -ENOENT ? -ESRCH : r;
e79f68d1
ZJS
728
729 d = endswith(*name, " (deleted)");
730 if (d)
731 *d = '\0';
732
733 return 0;
87d2c1ff
LP
734}
735
901c3d0d 736static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
f74e605f 737 _cleanup_fclose_ FILE *f = NULL;
9db11a99 738 char line[LINE_MAX];
49aa47c7 739 const char *p;
7e4ab3c5 740
f74e605f 741 assert(field);
7e4ab3c5
LP
742 assert(uid);
743
744 if (pid == 0)
745 return getuid();
746
49aa47c7
LP
747 p = procfs_file_alloca(pid, "status");
748 f = fopen(p, "re");
7e4ab3c5
LP
749 if (!f)
750 return -errno;
751
9db11a99 752 FOREACH_LINE(line, f, return -errno) {
f74e605f 753 char *l;
7e4ab3c5
LP
754
755 l = strstrip(line);
756
901c3d0d
LP
757 if (startswith(l, field)) {
758 l += strlen(field);
7e4ab3c5
LP
759 l += strspn(l, WHITESPACE);
760
761 l[strcspn(l, WHITESPACE)] = 0;
762
f74e605f 763 return parse_uid(l, uid);
7e4ab3c5
LP
764 }
765 }
766
f74e605f 767 return -EIO;
7e4ab3c5
LP
768}
769
901c3d0d
LP
770int get_process_uid(pid_t pid, uid_t *uid) {
771 return get_process_id(pid, "Uid:", uid);
772}
773
774int get_process_gid(pid_t pid, gid_t *gid) {
49aa47c7 775 assert_cc(sizeof(uid_t) == sizeof(gid_t));
901c3d0d
LP
776 return get_process_id(pid, "Gid:", gid);
777}
778
fab56fc5
LP
779char *strnappend(const char *s, const char *suffix, size_t b) {
780 size_t a;
44d8db9e
LP
781 char *r;
782
fab56fc5
LP
783 if (!s && !suffix)
784 return strdup("");
785
786 if (!s)
787 return strndup(suffix, b);
788
789 if (!suffix)
790 return strdup(s);
791
44d8db9e
LP
792 assert(s);
793 assert(suffix);
794
795 a = strlen(s);
aa408e77 796 if (b > ((size_t) -1) - a)
040f18ea 797 return NULL;
44d8db9e 798
040f18ea
LP
799 r = new(char, a+b+1);
800 if (!r)
44d8db9e
LP
801 return NULL;
802
803 memcpy(r, s, a);
804 memcpy(r+a, suffix, b);
805 r[a+b] = 0;
806
807 return r;
808}
87f0e418 809
fab56fc5
LP
810char *strappend(const char *s, const char *suffix) {
811 return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
812}
813
87f0e418
LP
814int readlink_malloc(const char *p, char **r) {
815 size_t l = 100;
816
817 assert(p);
818 assert(r);
819
820 for (;;) {
821 char *c;
822 ssize_t n;
823
824 if (!(c = new(char, l)))
825 return -ENOMEM;
826
827 if ((n = readlink(p, c, l-1)) < 0) {
828 int ret = -errno;
829 free(c);
830 return ret;
831 }
832
833 if ((size_t) n < l-1) {
834 c[n] = 0;
835 *r = c;
836 return 0;
837 }
838
839 free(c);
840 l *= 2;
841 }
842}
843
2c7108c4 844int readlink_and_make_absolute(const char *p, char **r) {
1058cbf2
ZJS
845 _cleanup_free_ char *target = NULL;
846 char *k;
2c7108c4
LP
847 int j;
848
849 assert(p);
850 assert(r);
851
1058cbf2
ZJS
852 j = readlink_malloc(p, &target);
853 if (j < 0)
2c7108c4
LP
854 return j;
855
856 k = file_in_same_dir(p, target);
2c7108c4
LP
857 if (!k)
858 return -ENOMEM;
859
860 *r = k;
861 return 0;
862}
863
83096483
LP
864int readlink_and_canonicalize(const char *p, char **r) {
865 char *t, *s;
866 int j;
867
868 assert(p);
869 assert(r);
870
871 j = readlink_and_make_absolute(p, &t);
872 if (j < 0)
873 return j;
874
875 s = canonicalize_file_name(t);
876 if (s) {
877 free(t);
878 *r = s;
879 } else
880 *r = t;
881
882 path_kill_slashes(*r);
883
884 return 0;
885}
886
2a987ee8
LP
887int reset_all_signal_handlers(void) {
888 int sig;
889
890 for (sig = 1; sig < _NSIG; sig++) {
b92bea5d
ZJS
891 struct sigaction sa = {
892 .sa_handler = SIG_DFL,
893 .sa_flags = SA_RESTART,
894 };
2a987ee8
LP
895
896 if (sig == SIGKILL || sig == SIGSTOP)
897 continue;
898
2a987ee8
LP
899 /* On Linux the first two RT signals are reserved by
900 * glibc, and sigaction() will return EINVAL for them. */
901 if ((sigaction(sig, &sa, NULL) < 0))
902 if (errno != EINVAL)
903 return -errno;
904 }
905
8e274523 906 return 0;
2a987ee8 907}
4a72ff34
LP
908
909char *strstrip(char *s) {
57a8eca8 910 char *e;
4a72ff34
LP
911
912 /* Drops trailing whitespace. Modifies the string in
913 * place. Returns pointer to first non-space character */
914
915 s += strspn(s, WHITESPACE);
916
57a8eca8
LP
917 for (e = strchr(s, 0); e > s; e --)
918 if (!strchr(WHITESPACE, e[-1]))
919 break;
4a72ff34 920
57a8eca8 921 *e = 0;
4a72ff34
LP
922
923 return s;
4a72ff34
LP
924}
925
ee9b5e01
LP
926char *delete_chars(char *s, const char *bad) {
927 char *f, *t;
928
929 /* Drops all whitespace, regardless where in the string */
930
931 for (f = s, t = s; *f; f++) {
932 if (strchr(bad, *f))
933 continue;
934
935 *(t++) = *f;
936 }
937
938 *t = 0;
939
940 return s;
941}
942
ab1f0633
LP
943bool in_charset(const char *s, const char* charset) {
944 const char *i;
945
946 assert(s);
947 assert(charset);
948
949 for (i = s; *i; i++)
950 if (!strchr(charset, *i))
951 return false;
952
953 return true;
954}
955
4a72ff34
LP
956char *file_in_same_dir(const char *path, const char *filename) {
957 char *e, *r;
958 size_t k;
959
960 assert(path);
961 assert(filename);
962
963 /* This removes the last component of path and appends
964 * filename, unless the latter is absolute anyway or the
965 * former isn't */
966
967 if (path_is_absolute(filename))
968 return strdup(filename);
969
970 if (!(e = strrchr(path, '/')))
971 return strdup(filename);
972
973 k = strlen(filename);
974 if (!(r = new(char, e-path+1+k+1)))
975 return NULL;
976
977 memcpy(r, path, e-path+1);
978 memcpy(r+(e-path)+1, filename, k+1);
979
980 return r;
981}
fb624d04 982
c32dd69b
LP
983int rmdir_parents(const char *path, const char *stop) {
984 size_t l;
985 int r = 0;
986
987 assert(path);
988 assert(stop);
989
990 l = strlen(path);
991
992 /* Skip trailing slashes */
993 while (l > 0 && path[l-1] == '/')
994 l--;
995
996 while (l > 0) {
997 char *t;
998
999 /* Skip last component */
1000 while (l > 0 && path[l-1] != '/')
1001 l--;
1002
1003 /* Skip trailing slashes */
1004 while (l > 0 && path[l-1] == '/')
1005 l--;
1006
1007 if (l <= 0)
1008 break;
1009
1010 if (!(t = strndup(path, l)))
1011 return -ENOMEM;
1012
1013 if (path_startswith(stop, t)) {
1014 free(t);
1015 return 0;
1016 }
1017
1018 r = rmdir(t);
1019 free(t);
1020
1021 if (r < 0)
1022 if (errno != ENOENT)
1023 return -errno;
1024 }
1025
1026 return 0;
1027}
1028
fb624d04
LP
1029char hexchar(int x) {
1030 static const char table[16] = "0123456789abcdef";
1031
1032 return table[x & 15];
1033}
4fe88d28
LP
1034
1035int unhexchar(char c) {
1036
1037 if (c >= '0' && c <= '9')
1038 return c - '0';
1039
1040 if (c >= 'a' && c <= 'f')
ea430986 1041 return c - 'a' + 10;
4fe88d28
LP
1042
1043 if (c >= 'A' && c <= 'F')
ea430986 1044 return c - 'A' + 10;
4fe88d28
LP
1045
1046 return -1;
1047}
1048
66e35261
LP
1049char *hexmem(const void *p, size_t l) {
1050 char *r, *z;
1051 const uint8_t *x;
1052
1053 z = r = malloc(l * 2 + 1);
1054 if (!r)
1055 return NULL;
1056
1057 for (x = p; x < (const uint8_t*) p + l; x++) {
1058 *(z++) = hexchar(*x >> 4);
1059 *(z++) = hexchar(*x & 15);
1060 }
1061
1062 *z = 0;
1063 return r;
1064}
1065
2181a7f5
LP
1066void *unhexmem(const char *p, size_t l) {
1067 uint8_t *r, *z;
1068 const char *x;
1069
1070 assert(p);
1071
1072 z = r = malloc((l + 1) / 2 + 1);
1073 if (!r)
1074 return NULL;
1075
1076 for (x = p; x < p + l; x += 2) {
1077 int a, b;
1078
1079 a = unhexchar(x[0]);
1080 if (x+1 < p + l)
1081 b = unhexchar(x[1]);
1082 else
1083 b = 0;
1084
1085 *(z++) = (uint8_t) a << 4 | (uint8_t) b;
1086 }
1087
1088 *z = 0;
1089 return r;
1090}
1091
4fe88d28
LP
1092char octchar(int x) {
1093 return '0' + (x & 7);
1094}
1095
1096int unoctchar(char c) {
1097
1098 if (c >= '0' && c <= '7')
1099 return c - '0';
1100
1101 return -1;
1102}
1103
5af98f82
LP
1104char decchar(int x) {
1105 return '0' + (x % 10);
1106}
1107
1108int undecchar(char c) {
1109
1110 if (c >= '0' && c <= '9')
1111 return c - '0';
1112
1113 return -1;
1114}
1115
4fe88d28
LP
1116char *cescape(const char *s) {
1117 char *r, *t;
1118 const char *f;
1119
1120 assert(s);
1121
1122 /* Does C style string escaping. */
1123
f8e2fb7b
LP
1124 r = new(char, strlen(s)*4 + 1);
1125 if (!r)
4fe88d28
LP
1126 return NULL;
1127
1128 for (f = s, t = r; *f; f++)
1129
1130 switch (*f) {
1131
1132 case '\a':
1133 *(t++) = '\\';
1134 *(t++) = 'a';
1135 break;
1136 case '\b':
1137 *(t++) = '\\';
1138 *(t++) = 'b';
1139 break;
1140 case '\f':
1141 *(t++) = '\\';
1142 *(t++) = 'f';
1143 break;
1144 case '\n':
1145 *(t++) = '\\';
1146 *(t++) = 'n';
1147 break;
1148 case '\r':
1149 *(t++) = '\\';
1150 *(t++) = 'r';
1151 break;
1152 case '\t':
1153 *(t++) = '\\';
1154 *(t++) = 't';
1155 break;
1156 case '\v':
1157 *(t++) = '\\';
1158 *(t++) = 'v';
1159 break;
1160 case '\\':
1161 *(t++) = '\\';
1162 *(t++) = '\\';
1163 break;
1164 case '"':
1165 *(t++) = '\\';
1166 *(t++) = '"';
1167 break;
1168 case '\'':
1169 *(t++) = '\\';
1170 *(t++) = '\'';
1171 break;
1172
1173 default:
1174 /* For special chars we prefer octal over
1175 * hexadecimal encoding, simply because glib's
1176 * g_strescape() does the same */
1177 if ((*f < ' ') || (*f >= 127)) {
1178 *(t++) = '\\';
1179 *(t++) = octchar((unsigned char) *f >> 6);
1180 *(t++) = octchar((unsigned char) *f >> 3);
1181 *(t++) = octchar((unsigned char) *f);
1182 } else
1183 *(t++) = *f;
1184 break;
1185 }
1186
1187 *t = 0;
1188
1189 return r;
1190}
1191
5b4c61cd 1192char *cunescape_length_with_prefix(const char *s, size_t length, const char *prefix) {
4fe88d28
LP
1193 char *r, *t;
1194 const char *f;
5b4c61cd 1195 size_t pl;
4fe88d28
LP
1196
1197 assert(s);
1198
5b4c61cd
LP
1199 /* Undoes C style string escaping, and optionally prefixes it. */
1200
1201 pl = prefix ? strlen(prefix) : 0;
4fe88d28 1202
5b4c61cd 1203 r = new(char, pl+length+1);
7f110ff9 1204 if (!r)
4fe88d28
LP
1205 return r;
1206
5b4c61cd
LP
1207 if (prefix)
1208 memcpy(r, prefix, pl);
1209
1210 for (f = s, t = r + pl; f < s + length; f++) {
4fe88d28
LP
1211
1212 if (*f != '\\') {
1213 *(t++) = *f;
1214 continue;
1215 }
1216
1217 f++;
1218
1219 switch (*f) {
1220
1221 case 'a':
1222 *(t++) = '\a';
1223 break;
1224 case 'b':
1225 *(t++) = '\b';
1226 break;
1227 case 'f':
1228 *(t++) = '\f';
1229 break;
1230 case 'n':
1231 *(t++) = '\n';
1232 break;
1233 case 'r':
1234 *(t++) = '\r';
1235 break;
1236 case 't':
1237 *(t++) = '\t';
1238 break;
1239 case 'v':
1240 *(t++) = '\v';
1241 break;
1242 case '\\':
1243 *(t++) = '\\';
1244 break;
1245 case '"':
1246 *(t++) = '"';
1247 break;
1248 case '\'':
1249 *(t++) = '\'';
1250 break;
1251
e167fb86
LP
1252 case 's':
1253 /* This is an extension of the XDG syntax files */
1254 *(t++) = ' ';
1255 break;
1256
4fe88d28
LP
1257 case 'x': {
1258 /* hexadecimal encoding */
1259 int a, b;
1260
7f110ff9
LP
1261 a = unhexchar(f[1]);
1262 b = unhexchar(f[2]);
1263
1264 if (a < 0 || b < 0) {
4fe88d28
LP
1265 /* Invalid escape code, let's take it literal then */
1266 *(t++) = '\\';
1267 *(t++) = 'x';
1268 } else {
1269 *(t++) = (char) ((a << 4) | b);
1270 f += 2;
1271 }
1272
1273 break;
1274 }
1275
1276 case '0':
1277 case '1':
1278 case '2':
1279 case '3':
1280 case '4':
1281 case '5':
1282 case '6':
1283 case '7': {
1284 /* octal encoding */
1285 int a, b, c;
1286
7f110ff9
LP
1287 a = unoctchar(f[0]);
1288 b = unoctchar(f[1]);
1289 c = unoctchar(f[2]);
1290
1291 if (a < 0 || b < 0 || c < 0) {
4fe88d28
LP
1292 /* Invalid escape code, let's take it literal then */
1293 *(t++) = '\\';
1294 *(t++) = f[0];
1295 } else {
1296 *(t++) = (char) ((a << 6) | (b << 3) | c);
1297 f += 2;
1298 }
1299
1300 break;
1301 }
1302
1303 case 0:
1304 /* premature end of string.*/
1305 *(t++) = '\\';
1306 goto finish;
1307
1308 default:
1309 /* Invalid escape code, let's take it literal then */
1310 *(t++) = '\\';
f3d4cc01 1311 *(t++) = *f;
4fe88d28
LP
1312 break;
1313 }
1314 }
1315
1316finish:
1317 *t = 0;
1318 return r;
1319}
1320
5b4c61cd
LP
1321char *cunescape_length(const char *s, size_t length) {
1322 return cunescape_length_with_prefix(s, length, NULL);
1323}
1324
6febfd0d 1325char *cunescape(const char *s) {
5b4c61cd
LP
1326 assert(s);
1327
6febfd0d
LP
1328 return cunescape_length(s, strlen(s));
1329}
4fe88d28
LP
1330
1331char *xescape(const char *s, const char *bad) {
1332 char *r, *t;
1333 const char *f;
1334
1335 /* Escapes all chars in bad, in addition to \ and all special
1336 * chars, in \xFF style escaping. May be reversed with
1337 * cunescape. */
1338
08ace05b
LP
1339 r = new(char, strlen(s) * 4 + 1);
1340 if (!r)
4fe88d28
LP
1341 return NULL;
1342
1343 for (f = s, t = r; *f; f++) {
1344
b866264a
LP
1345 if ((*f < ' ') || (*f >= 127) ||
1346 (*f == '\\') || strchr(bad, *f)) {
4fe88d28
LP
1347 *(t++) = '\\';
1348 *(t++) = 'x';
1349 *(t++) = hexchar(*f >> 4);
1350 *(t++) = hexchar(*f);
1351 } else
1352 *(t++) = *f;
1353 }
1354
1355 *t = 0;
1356
1357 return r;
1358}
1359
67d51650 1360char *ascii_strlower(char *t) {
4fe88d28
LP
1361 char *p;
1362
67d51650 1363 assert(t);
4fe88d28 1364
67d51650 1365 for (p = t; *p; p++)
4fe88d28
LP
1366 if (*p >= 'A' && *p <= 'Z')
1367 *p = *p - 'A' + 'a';
1368
67d51650 1369 return t;
4fe88d28 1370}
1dccbe19 1371
44a6b1b6 1372_pure_ static bool ignore_file_allow_backup(const char *filename) {
c85dc17b
LP
1373 assert(filename);
1374
1375 return
1376 filename[0] == '.' ||
6c78be3c 1377 streq(filename, "lost+found") ||
e472d476
LP
1378 streq(filename, "aquota.user") ||
1379 streq(filename, "aquota.group") ||
c85dc17b
LP
1380 endswith(filename, ".rpmnew") ||
1381 endswith(filename, ".rpmsave") ||
1382 endswith(filename, ".rpmorig") ||
1383 endswith(filename, ".dpkg-old") ||
1384 endswith(filename, ".dpkg-new") ||
1385 endswith(filename, ".swp");
1386}
1387
a228a22f
LP
1388bool ignore_file(const char *filename) {
1389 assert(filename);
1390
1391 if (endswith(filename, "~"))
1392 return false;
1393
1394 return ignore_file_allow_backup(filename);
1395}
1396
3a0ecb08
LP
1397int fd_nonblock(int fd, bool nonblock) {
1398 int flags;
1399
1400 assert(fd >= 0);
1401
1402 if ((flags = fcntl(fd, F_GETFL, 0)) < 0)
1403 return -errno;
1404
1405 if (nonblock)
1406 flags |= O_NONBLOCK;
1407 else
1408 flags &= ~O_NONBLOCK;
1409
1410 if (fcntl(fd, F_SETFL, flags) < 0)
1411 return -errno;
1412
1413 return 0;
1414}
1415
1416int fd_cloexec(int fd, bool cloexec) {
1417 int flags;
1418
1419 assert(fd >= 0);
1420
1421 if ((flags = fcntl(fd, F_GETFD, 0)) < 0)
1422 return -errno;
1423
1424 if (cloexec)
1425 flags |= FD_CLOEXEC;
1426 else
1427 flags &= ~FD_CLOEXEC;
1428
1429 if (fcntl(fd, F_SETFD, flags) < 0)
1430 return -errno;
1431
1432 return 0;
1433}
1434
44a6b1b6 1435_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) {
b19be9eb
LP
1436 unsigned i;
1437
1438 assert(n_fdset == 0 || fdset);
1439
1440 for (i = 0; i < n_fdset; i++)
1441 if (fdset[i] == fd)
1442 return true;
1443
1444 return false;
1445}
1446
a0d40ac5
LP
1447int close_all_fds(const int except[], unsigned n_except) {
1448 DIR *d;
1449 struct dirent *de;
1450 int r = 0;
1451
b19be9eb
LP
1452 assert(n_except == 0 || except);
1453
1454 d = opendir("/proc/self/fd");
1455 if (!d) {
1456 int fd;
1457 struct rlimit rl;
1458
1459 /* When /proc isn't available (for example in chroots)
1460 * the fallback is brute forcing through the fd
1461 * table */
1462
1463 assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0);
1464 for (fd = 3; fd < (int) rl.rlim_max; fd ++) {
1465
1466 if (fd_in_set(fd, except, n_except))
1467 continue;
1468
1469 if (close_nointr(fd) < 0)
1470 if (errno != EBADF && r == 0)
1471 r = -errno;
1472 }
1473
1474 return r;
1475 }
a0d40ac5
LP
1476
1477 while ((de = readdir(d))) {
a7610064 1478 int fd = -1;
a0d40ac5 1479
a16e1123 1480 if (ignore_file(de->d_name))
a0d40ac5
LP
1481 continue;
1482
720ce21d
LP
1483 if (safe_atoi(de->d_name, &fd) < 0)
1484 /* Let's better ignore this, just in case */
1485 continue;
a0d40ac5
LP
1486
1487 if (fd < 3)
1488 continue;
1489
1490 if (fd == dirfd(d))
1491 continue;
1492
b19be9eb
LP
1493 if (fd_in_set(fd, except, n_except))
1494 continue;
a0d40ac5 1495
720ce21d 1496 if (close_nointr(fd) < 0) {
2f357920 1497 /* Valgrind has its own FD and doesn't want to have it closed */
720ce21d
LP
1498 if (errno != EBADF && r == 0)
1499 r = -errno;
2f357920 1500 }
a0d40ac5
LP
1501 }
1502
a0d40ac5
LP
1503 closedir(d);
1504 return r;
1505}
1506
db12775d
LP
1507bool chars_intersect(const char *a, const char *b) {
1508 const char *p;
1509
1510 /* Returns true if any of the chars in a are in b. */
1511 for (p = a; *p; p++)
1512 if (strchr(b, *p))
1513 return true;
1514
1515 return false;
1516}
1517
42856c10 1518bool fstype_is_network(const char *fstype) {
a05f97b3
LP
1519 static const char table[] =
1520 "cifs\0"
1521 "smbfs\0"
1522 "ncpfs\0"
dac70dc7 1523 "ncp\0"
a05f97b3
LP
1524 "nfs\0"
1525 "nfs4\0"
1526 "gfs\0"
73836c5c 1527 "gfs2\0";
42856c10 1528
a05f97b3 1529 return nulstr_contains(table, fstype);
42856c10
LP
1530}
1531
601f6a1e 1532int chvt(int vt) {
a05f97b3 1533 _cleanup_close_ int fd;
601f6a1e 1534
a05f97b3
LP
1535 fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
1536 if (fd < 0)
601f6a1e
LP
1537 return -errno;
1538
1539 if (vt < 0) {
1540 int tiocl[2] = {
1541 TIOCL_GETKMSGREDIRECT,
1542 0
1543 };
1544
a05f97b3
LP
1545 if (ioctl(fd, TIOCLINUX, tiocl) < 0)
1546 return -errno;
601f6a1e
LP
1547
1548 vt = tiocl[0] <= 0 ? 1 : tiocl[0];
1549 }
1550
1551 if (ioctl(fd, VT_ACTIVATE, vt) < 0)
a05f97b3 1552 return -errno;
601f6a1e 1553
a05f97b3 1554 return 0;
601f6a1e
LP
1555}
1556
8f2d43a0 1557int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) {
80876c20
LP
1558 struct termios old_termios, new_termios;
1559 char c;
20c03b7b 1560 char line[LINE_MAX];
80876c20
LP
1561
1562 assert(f);
1563 assert(ret);
1564
1565 if (tcgetattr(fileno(f), &old_termios) >= 0) {
1566 new_termios = old_termios;
1567
1568 new_termios.c_lflag &= ~ICANON;
1569 new_termios.c_cc[VMIN] = 1;
1570 new_termios.c_cc[VTIME] = 0;
1571
1572 if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) {
1573 size_t k;
1574
8f2d43a0
LP
1575 if (t != (usec_t) -1) {
1576 if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0) {
1577 tcsetattr(fileno(f), TCSADRAIN, &old_termios);
1578 return -ETIMEDOUT;
1579 }
1580 }
1581
80876c20
LP
1582 k = fread(&c, 1, 1, f);
1583
1584 tcsetattr(fileno(f), TCSADRAIN, &old_termios);
1585
1586 if (k <= 0)
1587 return -EIO;
1588
1589 if (need_nl)
1590 *need_nl = c != '\n';
1591
1592 *ret = c;
1593 return 0;
1594 }
1595 }
1596
8f2d43a0
LP
1597 if (t != (usec_t) -1)
1598 if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0)
1599 return -ETIMEDOUT;
1600
1601 if (!fgets(line, sizeof(line), f))
80876c20
LP
1602 return -EIO;
1603
1604 truncate_nl(line);
1605
1606 if (strlen(line) != 1)
1607 return -EBADMSG;
1608
1609 if (need_nl)
1610 *need_nl = false;
1611
1612 *ret = line[0];
1613 return 0;
1614}
1615
1616int ask(char *ret, const char *replies, const char *text, ...) {
1b39d4b9 1617
80876c20
LP
1618 assert(ret);
1619 assert(replies);
1620 assert(text);
1621
1622 for (;;) {
1623 va_list ap;
1624 char c;
1625 int r;
1626 bool need_nl = true;
1627
8481248b 1628 if (on_tty())
c1072ea0 1629 fputs(ANSI_HIGHLIGHT_ON, stdout);
b1b2dc0c 1630
80876c20
LP
1631 va_start(ap, text);
1632 vprintf(text, ap);
1633 va_end(ap);
1634
8481248b 1635 if (on_tty())
c1072ea0 1636 fputs(ANSI_HIGHLIGHT_OFF, stdout);
b1b2dc0c 1637
80876c20
LP
1638 fflush(stdout);
1639
8f2d43a0
LP
1640 r = read_one_char(stdin, &c, (usec_t) -1, &need_nl);
1641 if (r < 0) {
80876c20
LP
1642
1643 if (r == -EBADMSG) {
1644 puts("Bad input, please try again.");
1645 continue;
1646 }
1647
1648 putchar('\n');
1649 return r;
1650 }
1651
1652 if (need_nl)
1653 putchar('\n');
1654
1655 if (strchr(replies, c)) {
1656 *ret = c;
1657 return 0;
1658 }
1659
1660 puts("Read unexpected character, please try again.");
1661 }
1662}
1663
512947d4 1664int reset_terminal_fd(int fd, bool switch_to_text) {
80876c20
LP
1665 struct termios termios;
1666 int r = 0;
3fe5e5d4
LP
1667
1668 /* Set terminal to some sane defaults */
80876c20
LP
1669
1670 assert(fd >= 0);
1671
eed1d0e3
LP
1672 /* We leave locked terminal attributes untouched, so that
1673 * Plymouth may set whatever it wants to set, and we don't
1674 * interfere with that. */
3fe5e5d4
LP
1675
1676 /* Disable exclusive mode, just in case */
1677 ioctl(fd, TIOCNXCL);
1678
5c0100a5 1679 /* Switch to text mode */
512947d4
MS
1680 if (switch_to_text)
1681 ioctl(fd, KDSETMODE, KD_TEXT);
5c0100a5 1682
3fe5e5d4 1683 /* Enable console unicode mode */
df465b3f 1684 ioctl(fd, KDSKBMODE, K_UNICODE);
80876c20
LP
1685
1686 if (tcgetattr(fd, &termios) < 0) {
1687 r = -errno;
1688 goto finish;
1689 }
1690
aaf694ca
LP
1691 /* We only reset the stuff that matters to the software. How
1692 * hardware is set up we don't touch assuming that somebody
1693 * else will do that for us */
1694
1695 termios.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | IUCLC);
80876c20
LP
1696 termios.c_iflag |= ICRNL | IMAXBEL | IUTF8;
1697 termios.c_oflag |= ONLCR;
1698 termios.c_cflag |= CREAD;
1699 termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOPRT | ECHOKE;
1700
1701 termios.c_cc[VINTR] = 03; /* ^C */
1702 termios.c_cc[VQUIT] = 034; /* ^\ */
1703 termios.c_cc[VERASE] = 0177;
1704 termios.c_cc[VKILL] = 025; /* ^X */
1705 termios.c_cc[VEOF] = 04; /* ^D */
1706 termios.c_cc[VSTART] = 021; /* ^Q */
1707 termios.c_cc[VSTOP] = 023; /* ^S */
1708 termios.c_cc[VSUSP] = 032; /* ^Z */
1709 termios.c_cc[VLNEXT] = 026; /* ^V */
1710 termios.c_cc[VWERASE] = 027; /* ^W */
1711 termios.c_cc[VREPRINT] = 022; /* ^R */
aaf694ca
LP
1712 termios.c_cc[VEOL] = 0;
1713 termios.c_cc[VEOL2] = 0;
80876c20
LP
1714
1715 termios.c_cc[VTIME] = 0;
1716 termios.c_cc[VMIN] = 1;
1717
1718 if (tcsetattr(fd, TCSANOW, &termios) < 0)
1719 r = -errno;
1720
1721finish:
1722 /* Just in case, flush all crap out */
1723 tcflush(fd, TCIOFLUSH);
1724
1725 return r;
1726}
1727
6ea832a2
LP
1728int reset_terminal(const char *name) {
1729 int fd, r;
1730
1731 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
1732 if (fd < 0)
1733 return fd;
1734
512947d4 1735 r = reset_terminal_fd(fd, true);
6ea832a2
LP
1736 close_nointr_nofail(fd);
1737
1738 return r;
1739}
1740
80876c20
LP
1741int open_terminal(const char *name, int mode) {
1742 int fd, r;
f73f76ac 1743 unsigned c = 0;
80876c20 1744
f73f76ac
LP
1745 /*
1746 * If a TTY is in the process of being closed opening it might
1747 * cause EIO. This is horribly awful, but unlikely to be
1748 * changed in the kernel. Hence we work around this problem by
1749 * retrying a couple of times.
1750 *
1751 * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245
1752 */
1753
dd94c17e
LP
1754 assert(!(mode & O_CREAT));
1755
f73f76ac 1756 for (;;) {
dd94c17e 1757 fd = open(name, mode, 0);
af6da548 1758 if (fd >= 0)
f73f76ac
LP
1759 break;
1760
1761 if (errno != EIO)
1762 return -errno;
1763
af6da548 1764 /* Max 1s in total */
f73f76ac
LP
1765 if (c >= 20)
1766 return -errno;
1767
1768 usleep(50 * USEC_PER_MSEC);
1769 c++;
1770 }
1771
1772 if (fd < 0)
80876c20
LP
1773 return -errno;
1774
af6da548
LP
1775 r = isatty(fd);
1776 if (r < 0) {
80876c20
LP
1777 close_nointr_nofail(fd);
1778 return -errno;
1779 }
1780
1781 if (!r) {
1782 close_nointr_nofail(fd);
1783 return -ENOTTY;
1784 }
1785
1786 return fd;
1787}
1788
1789int flush_fd(int fd) {
b92bea5d
ZJS
1790 struct pollfd pollfd = {
1791 .fd = fd,
1792 .events = POLLIN,
1793 };
80876c20
LP
1794
1795 for (;;) {
20c03b7b 1796 char buf[LINE_MAX];
80876c20
LP
1797 ssize_t l;
1798 int r;
1799
e62d8c39
ZJS
1800 r = poll(&pollfd, 1, 0);
1801 if (r < 0) {
80876c20
LP
1802 if (errno == EINTR)
1803 continue;
1804
1805 return -errno;
80876c20 1806
e62d8c39 1807 } else if (r == 0)
80876c20
LP
1808 return 0;
1809
e62d8c39
ZJS
1810 l = read(fd, buf, sizeof(buf));
1811 if (l < 0) {
80876c20
LP
1812
1813 if (errno == EINTR)
1814 continue;
1815
1816 if (errno == EAGAIN)
1817 return 0;
1818
1819 return -errno;
e62d8c39 1820 } else if (l == 0)
80876c20
LP
1821 return 0;
1822 }
1823}
1824
af6da548
LP
1825int acquire_terminal(
1826 const char *name,
1827 bool fail,
1828 bool force,
1829 bool ignore_tiocstty_eperm,
1830 usec_t timeout) {
1831
4a0ff478 1832 int fd = -1, notify = -1, r = 0, wd = -1;
af6da548 1833 usec_t ts = 0;
80876c20
LP
1834
1835 assert(name);
1836
1837 /* We use inotify to be notified when the tty is closed. We
1838 * create the watch before checking if we can actually acquire
1839 * it, so that we don't lose any event.
1840 *
1841 * Note: strictly speaking this actually watches for the
1842 * device being closed, it does *not* really watch whether a
1843 * tty loses its controlling process. However, unless some
1844 * rogue process uses TIOCNOTTY on /dev/tty *after* closing
1845 * its tty otherwise this will not become a problem. As long
1846 * as the administrator makes sure not configure any service
1847 * on the same tty as an untrusted user this should not be a
1848 * problem. (Which he probably should not do anyway.) */
1849
af6da548
LP
1850 if (timeout != (usec_t) -1)
1851 ts = now(CLOCK_MONOTONIC);
1852
80876c20 1853 if (!fail && !force) {
af6da548
LP
1854 notify = inotify_init1(IN_CLOEXEC | (timeout != (usec_t) -1 ? IN_NONBLOCK : 0));
1855 if (notify < 0) {
80876c20
LP
1856 r = -errno;
1857 goto fail;
1858 }
1859
af6da548
LP
1860 wd = inotify_add_watch(notify, name, IN_CLOSE);
1861 if (wd < 0) {
80876c20
LP
1862 r = -errno;
1863 goto fail;
1864 }
1865 }
1866
1867 for (;;) {
b92bea5d
ZJS
1868 struct sigaction sa_old, sa_new = {
1869 .sa_handler = SIG_IGN,
1870 .sa_flags = SA_RESTART,
1871 };
1872
af6da548
LP
1873 if (notify >= 0) {
1874 r = flush_fd(notify);
1875 if (r < 0)
e3d1855b 1876 goto fail;
af6da548 1877 }
80876c20
LP
1878
1879 /* We pass here O_NOCTTY only so that we can check the return
1880 * value TIOCSCTTY and have a reliable way to figure out if we
1881 * successfully became the controlling process of the tty */
af6da548
LP
1882 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
1883 if (fd < 0)
6ea832a2 1884 return fd;
80876c20 1885
32c4bef8
LP
1886 /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
1887 * if we already own the tty. */
32c4bef8
LP
1888 assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
1889
80876c20 1890 /* First, try to get the tty */
32c4bef8
LP
1891 if (ioctl(fd, TIOCSCTTY, force) < 0)
1892 r = -errno;
1893
1894 assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
21de3988
LP
1895
1896 /* Sometimes it makes sense to ignore TIOCSCTTY
1897 * returning EPERM, i.e. when very likely we already
1898 * are have this controlling terminal. */
32c4bef8 1899 if (r < 0 && r == -EPERM && ignore_tiocstty_eperm)
21de3988
LP
1900 r = 0;
1901
32c4bef8 1902 if (r < 0 && (force || fail || r != -EPERM)) {
80876c20
LP
1903 goto fail;
1904 }
1905
1906 if (r >= 0)
1907 break;
1908
1909 assert(!fail);
1910 assert(!force);
1911 assert(notify >= 0);
1912
1913 for (;;) {
f601daa7 1914 uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX];
80876c20 1915 ssize_t l;
f601daa7 1916 struct inotify_event *e;
80876c20 1917
af6da548
LP
1918 if (timeout != (usec_t) -1) {
1919 usec_t n;
1920
1921 n = now(CLOCK_MONOTONIC);
1922 if (ts + timeout < n) {
1923 r = -ETIMEDOUT;
1924 goto fail;
1925 }
1926
1927 r = fd_wait_for_event(fd, POLLIN, ts + timeout - n);
1928 if (r < 0)
1929 goto fail;
1930
1931 if (r == 0) {
1932 r = -ETIMEDOUT;
1933 goto fail;
1934 }
1935 }
1936
1937 l = read(notify, inotify_buffer, sizeof(inotify_buffer));
1938 if (l < 0) {
80876c20 1939
af6da548 1940 if (errno == EINTR || errno == EAGAIN)
f601daa7
LP
1941 continue;
1942
1943 r = -errno;
1944 goto fail;
1945 }
1946
1947 e = (struct inotify_event*) inotify_buffer;
80876c20 1948
f601daa7
LP
1949 while (l > 0) {
1950 size_t step;
80876c20 1951
f601daa7 1952 if (e->wd != wd || !(e->mask & IN_CLOSE)) {
80876c20 1953 r = -EIO;
f601daa7
LP
1954 goto fail;
1955 }
80876c20 1956
f601daa7
LP
1957 step = sizeof(struct inotify_event) + e->len;
1958 assert(step <= (size_t) l);
80876c20 1959
f601daa7
LP
1960 e = (struct inotify_event*) ((uint8_t*) e + step);
1961 l -= step;
80876c20
LP
1962 }
1963
1964 break;
1965 }
1966
1967 /* We close the tty fd here since if the old session
1968 * ended our handle will be dead. It's important that
1969 * we do this after sleeping, so that we don't enter
1970 * an endless loop. */
1971 close_nointr_nofail(fd);
1972 }
1973
1974 if (notify >= 0)
a16e1123 1975 close_nointr_nofail(notify);
80876c20 1976
512947d4
MS
1977 r = reset_terminal_fd(fd, true);
1978 if (r < 0)
80876c20
LP
1979 log_warning("Failed to reset terminal: %s", strerror(-r));
1980
1981 return fd;
1982
1983fail:
1984 if (fd >= 0)
a16e1123 1985 close_nointr_nofail(fd);
80876c20
LP
1986
1987 if (notify >= 0)
a16e1123 1988 close_nointr_nofail(notify);
80876c20
LP
1989
1990 return r;
1991}
1992
1993int release_terminal(void) {
e62d8c39 1994 int r = 0;
b92bea5d
ZJS
1995 struct sigaction sa_old, sa_new = {
1996 .sa_handler = SIG_IGN,
1997 .sa_flags = SA_RESTART,
1998 };
7fd1b19b 1999 _cleanup_close_ int fd;
80876c20 2000
e62d8c39
ZJS
2001 fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY|O_CLOEXEC);
2002 if (fd < 0)
80876c20
LP
2003 return -errno;
2004
57cd2192
LP
2005 /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
2006 * by our own TIOCNOTTY */
57cd2192
LP
2007 assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
2008
80876c20
LP
2009 if (ioctl(fd, TIOCNOTTY) < 0)
2010 r = -errno;
2011
57cd2192
LP
2012 assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
2013
80876c20
LP
2014 return r;
2015}
2016
9a34ec5f
LP
2017int sigaction_many(const struct sigaction *sa, ...) {
2018 va_list ap;
2019 int r = 0, sig;
2020
2021 va_start(ap, sa);
2022 while ((sig = va_arg(ap, int)) > 0)
2023 if (sigaction(sig, sa, NULL) < 0)
2024 r = -errno;
2025 va_end(ap);
2026
2027 return r;
2028}
2029
2030int ignore_signals(int sig, ...) {
b92bea5d
ZJS
2031 struct sigaction sa = {
2032 .sa_handler = SIG_IGN,
2033 .sa_flags = SA_RESTART,
2034 };
9a34ec5f
LP
2035 va_list ap;
2036 int r = 0;
a337c6fc 2037
a337c6fc 2038
9a34ec5f
LP
2039 if (sigaction(sig, &sa, NULL) < 0)
2040 r = -errno;
2041
2042 va_start(ap, sig);
2043 while ((sig = va_arg(ap, int)) > 0)
2044 if (sigaction(sig, &sa, NULL) < 0)
2045 r = -errno;
2046 va_end(ap);
2047
2048 return r;
2049}
2050
2051int default_signals(int sig, ...) {
b92bea5d
ZJS
2052 struct sigaction sa = {
2053 .sa_handler = SIG_DFL,
2054 .sa_flags = SA_RESTART,
2055 };
9a34ec5f
LP
2056 va_list ap;
2057 int r = 0;
2058
9a34ec5f
LP
2059 if (sigaction(sig, &sa, NULL) < 0)
2060 r = -errno;
2061
2062 va_start(ap, sig);
2063 while ((sig = va_arg(ap, int)) > 0)
2064 if (sigaction(sig, &sa, NULL) < 0)
2065 r = -errno;
2066 va_end(ap);
2067
2068 return r;
a337c6fc
LP
2069}
2070
8d567588
LP
2071int close_pipe(int p[]) {
2072 int a = 0, b = 0;
2073
2074 assert(p);
2075
2076 if (p[0] >= 0) {
2077 a = close_nointr(p[0]);
2078 p[0] = -1;
2079 }
2080
2081 if (p[1] >= 0) {
2082 b = close_nointr(p[1]);
2083 p[1] = -1;
2084 }
2085
2086 return a < 0 ? a : b;
2087}
2088
eb22ac37 2089ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
8d567588
LP
2090 uint8_t *p;
2091 ssize_t n = 0;
2092
2093 assert(fd >= 0);
2094 assert(buf);
2095
2096 p = buf;
2097
2098 while (nbytes > 0) {
2099 ssize_t k;
2100
2101 if ((k = read(fd, p, nbytes)) <= 0) {
2102
eb22ac37 2103 if (k < 0 && errno == EINTR)
8d567588
LP
2104 continue;
2105
eb22ac37 2106 if (k < 0 && errno == EAGAIN && do_poll) {
b92bea5d
ZJS
2107 struct pollfd pollfd = {
2108 .fd = fd,
2109 .events = POLLIN,
2110 };
8d567588
LP
2111
2112 if (poll(&pollfd, 1, -1) < 0) {
2113 if (errno == EINTR)
2114 continue;
2115
2116 return n > 0 ? n : -errno;
2117 }
2118
c22ceead
CJ
2119 /* We knowingly ignore the revents value here,
2120 * and expect that any error/EOF is reported
2121 * via read()/write()
2122 */
8d567588
LP
2123
2124 continue;
2125 }
2126
2127 return n > 0 ? n : (k < 0 ? -errno : 0);
2128 }
2129
2130 p += k;
2131 nbytes -= k;
2132 n += k;
2133 }
2134
2135 return n;
2136}
2137
eb22ac37
LP
2138ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
2139 const uint8_t *p;
2140 ssize_t n = 0;
2141
2142 assert(fd >= 0);
2143 assert(buf);
2144
2145 p = buf;
2146
2147 while (nbytes > 0) {
2148 ssize_t k;
2149
fe652127
LP
2150 k = write(fd, p, nbytes);
2151 if (k <= 0) {
eb22ac37
LP
2152
2153 if (k < 0 && errno == EINTR)
2154 continue;
2155
2156 if (k < 0 && errno == EAGAIN && do_poll) {
b92bea5d
ZJS
2157 struct pollfd pollfd = {
2158 .fd = fd,
2159 .events = POLLOUT,
2160 };
eb22ac37
LP
2161
2162 if (poll(&pollfd, 1, -1) < 0) {
2163 if (errno == EINTR)
2164 continue;
2165
2166 return n > 0 ? n : -errno;
2167 }
2168
c22ceead
CJ
2169 /* We knowingly ignore the revents value here,
2170 * and expect that any error/EOF is reported
2171 * via read()/write()
2172 */
eb22ac37
LP
2173
2174 continue;
2175 }
2176
2177 return n > 0 ? n : (k < 0 ? -errno : 0);
2178 }
2179
2180 p += k;
2181 nbytes -= k;
2182 n += k;
2183 }
2184
2185 return n;
2186}
2187
ab1f0633
LP
2188int parse_bytes(const char *t, off_t *bytes) {
2189 static const struct {
2190 const char *suffix;
b32ff512 2191 unsigned long long factor;
ab1f0633
LP
2192 } table[] = {
2193 { "B", 1 },
2194 { "K", 1024ULL },
2195 { "M", 1024ULL*1024ULL },
2196 { "G", 1024ULL*1024ULL*1024ULL },
2197 { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
32895bb3
LP
2198 { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
2199 { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
ab1f0633
LP
2200 { "", 1 },
2201 };
2202
2203 const char *p;
b32ff512 2204 unsigned long long r = 0;
ab1f0633
LP
2205
2206 assert(t);
2207 assert(bytes);
2208
2209 p = t;
2210 do {
2211 long long l;
2212 char *e;
2213 unsigned i;
2214
2215 errno = 0;
2216 l = strtoll(p, &e, 10);
2217
8333c77e 2218 if (errno > 0)
ab1f0633
LP
2219 return -errno;
2220
2221 if (l < 0)
2222 return -ERANGE;
2223
2224 if (e == p)
2225 return -EINVAL;
2226
2227 e += strspn(e, WHITESPACE);
2228
2229 for (i = 0; i < ELEMENTSOF(table); i++)
2230 if (startswith(e, table[i].suffix)) {
b32ff512
ZJS
2231 unsigned long long tmp;
2232 if ((unsigned long long) l > ULLONG_MAX / table[i].factor)
2233 return -ERANGE;
2234 tmp = l * table[i].factor;
2235 if (tmp > ULLONG_MAX - r)
2236 return -ERANGE;
2237
2238 r += tmp;
2239 if ((unsigned long long) (off_t) r != r)
2240 return -ERANGE;
2241
ab1f0633
LP
2242 p = e + strlen(table[i].suffix);
2243 break;
2244 }
2245
2246 if (i >= ELEMENTSOF(table))
2247 return -EINVAL;
2248
b32ff512 2249 } while (*p);
ab1f0633
LP
2250
2251 *bytes = r;
2252
2253 return 0;
2254}
2255
843d2643
LP
2256int make_stdio(int fd) {
2257 int r, s, t;
2258
2259 assert(fd >= 0);
2260
73836c5c
LP
2261 r = dup3(fd, STDIN_FILENO, 0);
2262 s = dup3(fd, STDOUT_FILENO, 0);
2263 t = dup3(fd, STDERR_FILENO, 0);
843d2643
LP
2264
2265 if (fd >= 3)
2266 close_nointr_nofail(fd);
2267
2268 if (r < 0 || s < 0 || t < 0)
2269 return -errno;
2270
73836c5c 2271 /* We rely here that the new fd has O_CLOEXEC not set */
7862f62d 2272
843d2643
LP
2273 return 0;
2274}
2275
ade509ce
LP
2276int make_null_stdio(void) {
2277 int null_fd;
2278
cd3bd60a
LP
2279 null_fd = open("/dev/null", O_RDWR|O_NOCTTY);
2280 if (null_fd < 0)
ade509ce
LP
2281 return -errno;
2282
2283 return make_stdio(null_fd);
2284}
2285
8407a5d0
LP
2286bool is_device_path(const char *path) {
2287
2288 /* Returns true on paths that refer to a device, either in
2289 * sysfs or in /dev */
2290
2291 return
2292 path_startswith(path, "/dev/") ||
2293 path_startswith(path, "/sys/");
2294}
2295
01f78473 2296int dir_is_empty(const char *path) {
a05f97b3 2297 _cleanup_closedir_ DIR *d;
01f78473 2298
a05f97b3
LP
2299 d = opendir(path);
2300 if (!d)
01f78473
LP
2301 return -errno;
2302
2303 for (;;) {
7d5e9c0f 2304 struct dirent *de;
01f78473 2305
3fd11280
FW
2306 errno = 0;
2307 de = readdir(d);
2308 if (!de && errno != 0)
2309 return -errno;
01f78473 2310
a05f97b3
LP
2311 if (!de)
2312 return 1;
01f78473 2313
a05f97b3
LP
2314 if (!ignore_file(de->d_name))
2315 return 0;
2316 }
01f78473
LP
2317}
2318
844ec79b
ZJS
2319char* dirname_malloc(const char *path) {
2320 char *d, *dir, *dir2;
2321
2322 d = strdup(path);
2323 if (!d)
2324 return NULL;
2325 dir = dirname(d);
2326 assert(dir);
2327
2328 if (dir != d) {
2329 dir2 = strdup(dir);
2330 free(d);
2331 return dir2;
2332 }
2333
2334 return dir;
2335}
2336
9bf3b535
LP
2337void random_bytes(void *p, size_t n) {
2338 static bool srand_called = false;
a05f97b3 2339 _cleanup_close_ int fd;
9bf3b535
LP
2340 ssize_t k;
2341 uint8_t *q;
d3782d60 2342
ac0930c8
LP
2343 fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
2344 if (fd < 0)
d3782d60
LP
2345 goto fallback;
2346
9bf3b535
LP
2347 k = loop_read(fd, p, n, true);
2348 if (k < 0 || (size_t) k != n)
d3782d60
LP
2349 goto fallback;
2350
9bf3b535 2351 return;
d3782d60
LP
2352
2353fallback:
d3782d60 2354
9bf3b535 2355 if (!srand_called) {
a3b6fafe 2356
9bf3b535
LP
2357#ifdef HAVE_SYS_AUXV_H
2358 /* The kernel provides us with a bit of entropy in
2359 * auxv, so let's try to make use of that to seed the
2360 * pseudo-random generator. It's better than
2361 * nothing... */
a3b6fafe 2362
9bf3b535
LP
2363 void *auxv;
2364
2365 auxv = (void*) getauxval(AT_RANDOM);
2366 if (auxv)
2367 srand(*(unsigned*) auxv);
2368 else
2369#endif
2370 srand(time(NULL) + gettid());
a3b6fafe 2371
9bf3b535
LP
2372 srand_called = true;
2373 }
a3b6fafe 2374
9bf3b535
LP
2375 /* If some idiot made /dev/urandom unavailable to us, he'll
2376 * get a PRNG instead. */
2377 for (q = p; q < (uint8_t*) p + n; q ++)
2378 *q = rand();
a3b6fafe
LP
2379}
2380
5b6319dc
LP
2381void rename_process(const char name[8]) {
2382 assert(name);
2383
5d6b1584
LP
2384 /* This is a like a poor man's setproctitle(). It changes the
2385 * comm field, argv[0], and also the glibc's internally used
2386 * name of the process. For the first one a limit of 16 chars
2387 * applies, to the second one usually one of 10 (i.e. length
2388 * of "/sbin/init"), to the third one one of 7 (i.e. length of
2389 * "systemd"). If you pass a longer string it will be
2390 * truncated */
5b6319dc 2391
5d6b1584 2392 prctl(PR_SET_NAME, name);
5b6319dc
LP
2393
2394 if (program_invocation_name)
2395 strncpy(program_invocation_name, name, strlen(program_invocation_name));
9a0e6896
LP
2396
2397 if (saved_argc > 0) {
2398 int i;
2399
2400 if (saved_argv[0])
2401 strncpy(saved_argv[0], name, strlen(saved_argv[0]));
2402
2403 for (i = 1; i < saved_argc; i++) {
2404 if (!saved_argv[i])
2405 break;
2406
2407 memset(saved_argv[i], 0, strlen(saved_argv[i]));
2408 }
2409 }
5b6319dc
LP
2410}
2411
7d793605
LP
2412void sigset_add_many(sigset_t *ss, ...) {
2413 va_list ap;
2414 int sig;
2415
2416 assert(ss);
2417
2418 va_start(ap, ss);
2419 while ((sig = va_arg(ap, int)) > 0)
2420 assert_se(sigaddset(ss, sig) == 0);
2421 va_end(ap);
2422}
2423
ef2f1067
LP
2424char* gethostname_malloc(void) {
2425 struct utsname u;
2426
2427 assert_se(uname(&u) >= 0);
2428
344de609 2429 if (!isempty(u.nodename) && !streq(u.nodename, "(none)"))
ef2f1067
LP
2430 return strdup(u.nodename);
2431
2432 return strdup(u.sysname);
2433}
2434
344de609
LP
2435bool hostname_is_set(void) {
2436 struct utsname u;
2437
2438 assert_se(uname(&u) >= 0);
2439
2440 return !isempty(u.nodename) && !streq(u.nodename, "(none)");
2441}
2442
7c5f152a 2443static char *lookup_uid(uid_t uid) {
ef2f1067 2444 long bufsize;
a05f97b3
LP
2445 char *name;
2446 _cleanup_free_ char *buf = NULL;
ef2f1067 2447 struct passwd pwbuf, *pw = NULL;
ef2f1067
LP
2448
2449 /* Shortcut things to avoid NSS lookups */
2450 if (uid == 0)
2451 return strdup("root");
2452
7c5f152a
LP
2453 bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
2454 if (bufsize <= 0)
ef2f1067
LP
2455 bufsize = 4096;
2456
7c5f152a
LP
2457 buf = malloc(bufsize);
2458 if (!buf)
ef2f1067
LP
2459 return NULL;
2460
a05f97b3
LP
2461 if (getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0 && pw)
2462 return strdup(pw->pw_name);
ef2f1067
LP
2463
2464 if (asprintf(&name, "%lu", (unsigned long) uid) < 0)
2465 return NULL;
2466
2467 return name;
2468}
2469
7c5f152a
LP
2470char* getlogname_malloc(void) {
2471 uid_t uid;
2472 struct stat st;
2473
2474 if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0)
2475 uid = st.st_uid;
2476 else
2477 uid = getuid();
2478
2479 return lookup_uid(uid);
2480}
2481
2482char *getusername_malloc(void) {
2483 const char *e;
2484
2485 e = getenv("USER");
2486 if (e)
2487 return strdup(e);
2488
2489 return lookup_uid(getuid());
2490}
2491
fc116c6a
LP
2492int getttyname_malloc(int fd, char **r) {
2493 char path[PATH_MAX], *c;
618e02c7 2494 int k;
8c6db833
LP
2495
2496 assert(r);
ef2f1067 2497
a05f97b3 2498 k = ttyname_r(fd, path, sizeof(path));
27373e44 2499 if (k > 0)
618e02c7 2500 return -k;
ef2f1067
LP
2501
2502 char_array_0(path);
2503
a05f97b3
LP
2504 c = strdup(startswith(path, "/dev/") ? path + 5 : path);
2505 if (!c)
8c6db833
LP
2506 return -ENOMEM;
2507
2508 *r = c;
2509 return 0;
2510}
2511
fc116c6a
LP
2512int getttyname_harder(int fd, char **r) {
2513 int k;
2514 char *s;
2515
a05f97b3
LP
2516 k = getttyname_malloc(fd, &s);
2517 if (k < 0)
fc116c6a
LP
2518 return k;
2519
2520 if (streq(s, "tty")) {
2521 free(s);
4d6d6518 2522 return get_ctty(0, NULL, r);
fc116c6a
LP
2523 }
2524
2525 *r = s;
2526 return 0;
2527}
2528
4d6d6518 2529int get_ctty_devnr(pid_t pid, dev_t *d) {
49aa47c7
LP
2530 _cleanup_fclose_ FILE *f = NULL;
2531 char line[LINE_MAX], *p;
fc116c6a 2532 unsigned long ttynr;
49aa47c7 2533 const char *fn;
fc116c6a 2534
49aa47c7 2535 assert(pid >= 0);
49aa47c7 2536
b68fa010 2537 fn = procfs_file_alloca(pid, "stat");
4d6d6518
LP
2538
2539 f = fopen(fn, "re");
4d6d6518 2540 if (!f)
fc116c6a
LP
2541 return -errno;
2542
0bee65f0
LP
2543 if (!fgets(line, sizeof(line), f))
2544 return feof(f) ? -EIO : -errno;
fc116c6a 2545
4d6d6518
LP
2546 p = strrchr(line, ')');
2547 if (!p)
fc116c6a
LP
2548 return -EIO;
2549
2550 p++;
2551
2552 if (sscanf(p, " "
2553 "%*c " /* state */
2554 "%*d " /* ppid */
2555 "%*d " /* pgrp */
2556 "%*d " /* session */
2557 "%lu ", /* ttynr */
2558 &ttynr) != 1)
2559 return -EIO;
2560
11dc5d2b
LP
2561 if (major(ttynr) == 0 && minor(ttynr) == 0)
2562 return -ENOENT;
2563
0bee65f0
LP
2564 if (d)
2565 *d = (dev_t) ttynr;
2566
fc116c6a
LP
2567 return 0;
2568}
2569
4d6d6518 2570int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
fc116c6a 2571 int k;
fa70beaa 2572 char fn[sizeof("/dev/char/")-1 + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *s, *b, *p;
fc116c6a
LP
2573 dev_t devnr;
2574
2575 assert(r);
2576
4d6d6518
LP
2577 k = get_ctty_devnr(pid, &devnr);
2578 if (k < 0)
fc116c6a
LP
2579 return k;
2580
2581 snprintf(fn, sizeof(fn), "/dev/char/%u:%u", major(devnr), minor(devnr));
fc116c6a 2582
23406ce5
LP
2583 k = readlink_malloc(fn, &s);
2584 if (k < 0) {
fc116c6a
LP
2585
2586 if (k != -ENOENT)
2587 return k;
2588
46824d0e
LP
2589 /* This is an ugly hack */
2590 if (major(devnr) == 136) {
2591 if (asprintf(&b, "pts/%lu", (unsigned long) minor(devnr)) < 0)
2592 return -ENOMEM;
2593
2594 *r = b;
2595 if (_devnr)
2596 *_devnr = devnr;
2597
2598 return 0;
2599 }
2600
fc116c6a
LP
2601 /* Probably something like the ptys which have no
2602 * symlink in /dev/char. Let's return something
2603 * vaguely useful. */
2604
23406ce5
LP
2605 b = strdup(fn + 5);
2606 if (!b)
fc116c6a
LP
2607 return -ENOMEM;
2608
2609 *r = b;
46824d0e
LP
2610 if (_devnr)
2611 *_devnr = devnr;
2612
fc116c6a
LP
2613 return 0;
2614 }
2615
2616 if (startswith(s, "/dev/"))
2617 p = s + 5;
2618 else if (startswith(s, "../"))
2619 p = s + 3;
2620 else
2621 p = s;
2622
2623 b = strdup(p);
2624 free(s);
2625
2626 if (!b)
2627 return -ENOMEM;
2628
2629 *r = b;
46824d0e
LP
2630 if (_devnr)
2631 *_devnr = devnr;
2632
fc116c6a
LP
2633 return 0;
2634}
2635
f56d5db9 2636int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
8c6db833
LP
2637 DIR *d;
2638 int ret = 0;
2639
2640 assert(fd >= 0);
2641
2642 /* This returns the first error we run into, but nevertheless
7925c22a 2643 * tries to go on. This closes the passed fd. */
8c6db833 2644
d4d046e3
LP
2645 d = fdopendir(fd);
2646 if (!d) {
8c6db833 2647 close_nointr_nofail(fd);
4c633005
LP
2648
2649 return errno == ENOENT ? 0 : -errno;
8c6db833
LP
2650 }
2651
2652 for (;;) {
7d5e9c0f 2653 struct dirent *de;
7925c22a
LP
2654 bool is_dir, keep_around;
2655 struct stat st;
8c6db833
LP
2656 int r;
2657
3fd11280
FW
2658 errno = 0;
2659 de = readdir(d);
2660 if (!de && errno != 0) {
2661 if (ret == 0)
2662 ret = -errno;
8c6db833
LP
2663 break;
2664 }
2665
2666 if (!de)
2667 break;
2668
2669 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
2670 continue;
2671
7925c22a
LP
2672 if (de->d_type == DT_UNKNOWN ||
2673 honour_sticky ||
2674 (de->d_type == DT_DIR && root_dev)) {
8c6db833 2675 if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
4c633005 2676 if (ret == 0 && errno != ENOENT)
8c6db833
LP
2677 ret = -errno;
2678 continue;
2679 }
2680
2681 is_dir = S_ISDIR(st.st_mode);
7925c22a
LP
2682 keep_around =
2683 honour_sticky &&
2684 (st.st_uid == 0 || st.st_uid == getuid()) &&
2685 (st.st_mode & S_ISVTX);
ad293f5a 2686 } else {
8c6db833 2687 is_dir = de->d_type == DT_DIR;
7925c22a 2688 keep_around = false;
ad293f5a 2689 }
8c6db833
LP
2690
2691 if (is_dir) {
2692 int subdir_fd;
8c6db833 2693
597f43c7 2694 /* if root_dev is set, remove subdirectories only, if device is same as dir */
7925c22a
LP
2695 if (root_dev && st.st_dev != root_dev->st_dev)
2696 continue;
8c6db833 2697
7925c22a
LP
2698 subdir_fd = openat(fd, de->d_name,
2699 O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
2700 if (subdir_fd < 0) {
2701 if (ret == 0 && errno != ENOENT)
2702 ret = -errno;
2703 continue;
2704 }
2705
b3d28469 2706 r = rm_rf_children_dangerous(subdir_fd, only_dirs, honour_sticky, root_dev);
7925c22a
LP
2707 if (r < 0 && ret == 0)
2708 ret = r;
2709
2710 if (!keep_around)
2711 if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
ad293f5a
LP
2712 if (ret == 0 && errno != ENOENT)
2713 ret = -errno;
2714 }
2715
2716 } else if (!only_dirs && !keep_around) {
8c6db833
LP
2717
2718 if (unlinkat(fd, de->d_name, 0) < 0) {
4c633005 2719 if (ret == 0 && errno != ENOENT)
8c6db833
LP
2720 ret = -errno;
2721 }
2722 }
2723 }
2724
2725 closedir(d);
2726
2727 return ret;
2728}
2729
44a6b1b6 2730_pure_ static int is_temporary_fs(struct statfs *s) {
943aad8c 2731 assert(s);
73020ab2
SL
2732
2733 return F_TYPE_EQUAL(s->f_type, TMPFS_MAGIC) ||
2734 F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC);
943aad8c
ZJS
2735}
2736
f56d5db9
LP
2737int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
2738 struct statfs s;
2739
2740 assert(fd >= 0);
2741
2742 if (fstatfs(fd, &s) < 0) {
2743 close_nointr_nofail(fd);
2744 return -errno;
2745 }
2746
2747 /* We refuse to clean disk file systems with this call. This
2748 * is extra paranoia just to be sure we never ever remove
2749 * non-state data */
943aad8c 2750 if (!is_temporary_fs(&s)) {
f56d5db9
LP
2751 log_error("Attempted to remove disk file system, and we can't allow that.");
2752 close_nointr_nofail(fd);
2753 return -EPERM;
2754 }
2755
2756 return rm_rf_children_dangerous(fd, only_dirs, honour_sticky, root_dev);
2757}
2758
2759static int rm_rf_internal(const char *path, bool only_dirs, bool delete_root, bool honour_sticky, bool dangerous) {
2760 int fd, r;
2761 struct statfs s;
8c6db833
LP
2762
2763 assert(path);
2764
f56d5db9
LP
2765 /* We refuse to clean the root file system with this
2766 * call. This is extra paranoia to never cause a really
2767 * seriously broken system. */
2768 if (path_equal(path, "/")) {
2769 log_error("Attempted to remove entire root file system, and we can't allow that.");
2770 return -EPERM;
2771 }
461b1822 2772
d4d046e3
LP
2773 fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
2774 if (fd < 0) {
8c6db833
LP
2775
2776 if (errno != ENOTDIR)
2777 return -errno;
2778
f56d5db9
LP
2779 if (!dangerous) {
2780 if (statfs(path, &s) < 0)
2781 return -errno;
2782
943aad8c 2783 if (!is_temporary_fs(&s)) {
f56d5db9
LP
2784 log_error("Attempted to remove disk file system, and we can't allow that.");
2785 return -EPERM;
2786 }
2787 }
2788
8c6db833 2789 if (delete_root && !only_dirs)
d4d046e3 2790 if (unlink(path) < 0 && errno != ENOENT)
8c6db833
LP
2791 return -errno;
2792
2793 return 0;
2794 }
2795
f56d5db9
LP
2796 if (!dangerous) {
2797 if (fstatfs(fd, &s) < 0) {
2798 close_nointr_nofail(fd);
2799 return -errno;
2800 }
ad293f5a 2801
943aad8c 2802 if (!is_temporary_fs(&s)) {
f56d5db9
LP
2803 log_error("Attempted to remove disk file system, and we can't allow that.");
2804 close_nointr_nofail(fd);
2805 return -EPERM;
2806 }
2807 }
2808
2809 r = rm_rf_children_dangerous(fd, only_dirs, honour_sticky, NULL);
ad293f5a
LP
2810 if (delete_root) {
2811
8d53b453 2812 if (honour_sticky && file_is_priv_sticky(path) > 0)
ad293f5a 2813 return r;
8c6db833 2814
e27796a0 2815 if (rmdir(path) < 0 && errno != ENOENT) {
8c6db833
LP
2816 if (r == 0)
2817 r = -errno;
2818 }
ad293f5a 2819 }
8c6db833
LP
2820
2821 return r;
2822}
2823
f56d5db9
LP
2824int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) {
2825 return rm_rf_internal(path, only_dirs, delete_root, honour_sticky, false);
2826}
2827
2828int rm_rf_dangerous(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) {
2829 return rm_rf_internal(path, only_dirs, delete_root, honour_sticky, true);
2830}
2831
8c6db833
LP
2832int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
2833 assert(path);
2834
2835 /* Under the assumption that we are running privileged we
2836 * first change the access mode and only then hand out
2837 * ownership to avoid a window where access is too open. */
2838
8d53b453
LP
2839 if (mode != (mode_t) -1)
2840 if (chmod(path, mode) < 0)
2841 return -errno;
8c6db833 2842
8d53b453
LP
2843 if (uid != (uid_t) -1 || gid != (gid_t) -1)
2844 if (chown(path, uid, gid) < 0)
2845 return -errno;
8c6db833
LP
2846
2847 return 0;
ef2f1067
LP
2848}
2849
f4b47811
LP
2850int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) {
2851 assert(fd >= 0);
2852
2853 /* Under the assumption that we are running privileged we
2854 * first change the access mode and only then hand out
2855 * ownership to avoid a window where access is too open. */
2856
9588bc32
LP
2857 if (mode != (mode_t) -1)
2858 if (fchmod(fd, mode) < 0)
2859 return -errno;
f4b47811 2860
9588bc32
LP
2861 if (uid != (uid_t) -1 || gid != (gid_t) -1)
2862 if (fchown(fd, uid, gid) < 0)
2863 return -errno;
f4b47811
LP
2864
2865 return 0;
2866}
2867
82c121a4
LP
2868cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
2869 cpu_set_t *r;
2870 unsigned n = 1024;
2871
2872 /* Allocates the cpuset in the right size */
2873
2874 for (;;) {
2875 if (!(r = CPU_ALLOC(n)))
2876 return NULL;
2877
2878 if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), r) >= 0) {
2879 CPU_ZERO_S(CPU_ALLOC_SIZE(n), r);
2880
2881 if (ncpus)
2882 *ncpus = n;
2883
2884 return r;
2885 }
2886
2887 CPU_FREE(r);
2888
2889 if (errno != EINVAL)
2890 return NULL;
2891
2892 n *= 2;
2893 }
2894}
2895
984a2be4 2896int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) {
9ab7a8d2 2897 static const char status_indent[] = " "; /* "[" STATUS "] " */
669bec5d
LP
2898 _cleanup_free_ char *s = NULL;
2899 _cleanup_close_ int fd = -1;
b92bea5d 2900 struct iovec iovec[6] = {};
81beb750 2901 int n = 0;
984a2be4 2902 static bool prev_ephemeral;
9e58ff9c
LP
2903
2904 assert(format);
2905
9ab7a8d2 2906 /* This is independent of logging, as status messages are
9e58ff9c
LP
2907 * optional and go exclusively to the console. */
2908
2909 if (vasprintf(&s, format, ap) < 0)
669bec5d 2910 return log_oom();
9e58ff9c 2911
67e5cc4f 2912 fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
81beb750 2913 if (fd < 0)
669bec5d 2914 return fd;
9e58ff9c 2915
67e5cc4f 2916 if (ellipse) {
9ab7a8d2
MS
2917 char *e;
2918 size_t emax, sl;
2919 int c;
2920
67e5cc4f
LP
2921 c = fd_columns(fd);
2922 if (c <= 0)
2923 c = 80;
81beb750 2924
669bec5d 2925 sl = status ? sizeof(status_indent)-1 : 0;
9ab7a8d2
MS
2926
2927 emax = c - sl - 1;
2928 if (emax < 3)
2929 emax = 3;
81beb750 2930
67e5cc4f
LP
2931 e = ellipsize(s, emax, 75);
2932 if (e) {
2933 free(s);
2934 s = e;
2935 }
81beb750
LP
2936 }
2937
984a2be4
MS
2938 if (prev_ephemeral)
2939 IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE);
2940 prev_ephemeral = ephemeral;
2941
9ab7a8d2
MS
2942 if (status) {
2943 if (!isempty(status)) {
2944 IOVEC_SET_STRING(iovec[n++], "[");
2945 IOVEC_SET_STRING(iovec[n++], status);
2946 IOVEC_SET_STRING(iovec[n++], "] ");
2947 } else
2948 IOVEC_SET_STRING(iovec[n++], status_indent);
81beb750
LP
2949 }
2950
9ab7a8d2 2951 IOVEC_SET_STRING(iovec[n++], s);
984a2be4
MS
2952 if (!ephemeral)
2953 IOVEC_SET_STRING(iovec[n++], "\n");
81beb750 2954
669bec5d
LP
2955 if (writev(fd, iovec, n) < 0)
2956 return -errno;
9e58ff9c 2957
669bec5d 2958 return 0;
9e58ff9c
LP
2959}
2960
984a2be4 2961int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) {
c846ff47 2962 va_list ap;
669bec5d 2963 int r;
c846ff47
LP
2964
2965 assert(format);
2966
2967 va_start(ap, format);
984a2be4 2968 r = status_vprintf(status, ellipse, ephemeral, format, ap);
c846ff47 2969 va_end(ap);
669bec5d
LP
2970
2971 return r;
c846ff47
LP
2972}
2973
669bec5d 2974int status_welcome(void) {
669bec5d 2975 _cleanup_free_ char *pretty_name = NULL, *ansi_color = NULL;
9588bc32 2976 int r;
669bec5d
LP
2977
2978 r = parse_env_file("/etc/os-release", NEWLINE,
2979 "PRETTY_NAME", &pretty_name,
2980 "ANSI_COLOR", &ansi_color,
2981 NULL);
9588bc32 2982
669bec5d
LP
2983 if (r < 0 && r != -ENOENT)
2984 log_warning("Failed to read /etc/os-release: %s", strerror(-r));
2985
f620dff8 2986 return status_printf(NULL, false, false,
669bec5d
LP
2987 "\nWelcome to \x1B[%sm%s\x1B[0m!\n",
2988 isempty(ansi_color) ? "1" : ansi_color,
2989 isempty(pretty_name) ? "Linux" : pretty_name);
c846ff47
LP
2990}
2991
fab56fc5
LP
2992char *replace_env(const char *format, char **env) {
2993 enum {
2994 WORD,
c24eb49e 2995 CURLY,
fab56fc5
LP
2996 VARIABLE
2997 } state = WORD;
2998
2999 const char *e, *word = format;
3000 char *r = NULL, *k;
3001
3002 assert(format);
3003
3004 for (e = format; *e; e ++) {
3005
3006 switch (state) {
3007
3008 case WORD:
3009 if (*e == '$')
c24eb49e 3010 state = CURLY;
fab56fc5
LP
3011 break;
3012
c24eb49e
LP
3013 case CURLY:
3014 if (*e == '{') {
fab56fc5
LP
3015 if (!(k = strnappend(r, word, e-word-1)))
3016 goto fail;
3017
3018 free(r);
3019 r = k;
3020
3021 word = e-1;
3022 state = VARIABLE;
3023
3024 } else if (*e == '$') {
3025 if (!(k = strnappend(r, word, e-word)))
3026 goto fail;
3027
3028 free(r);
3029 r = k;
3030
3031 word = e+1;
3032 state = WORD;
3033 } else
3034 state = WORD;
3035 break;
3036
3037 case VARIABLE:
c24eb49e 3038 if (*e == '}') {
b95cf362 3039 const char *t;
fab56fc5 3040
4d1a6904 3041 t = strempty(strv_env_get_n(env, word+2, e-word-2));
fab56fc5 3042
4d1a6904
LP
3043 k = strappend(r, t);
3044 if (!k)
b95cf362 3045 goto fail;
fab56fc5 3046
b95cf362
LP
3047 free(r);
3048 r = k;
fab56fc5 3049
b95cf362 3050 word = e+1;
fab56fc5
LP
3051 state = WORD;
3052 }
3053 break;
3054 }
3055 }
3056
3057 if (!(k = strnappend(r, word, e-word)))
3058 goto fail;
3059
3060 free(r);
3061 return k;
3062
3063fail:
3064 free(r);
3065 return NULL;
3066}
3067
3068char **replace_env_argv(char **argv, char **env) {
3069 char **r, **i;
c24eb49e
LP
3070 unsigned k = 0, l = 0;
3071
3072 l = strv_length(argv);
fab56fc5 3073
c24eb49e 3074 if (!(r = new(char*, l+1)))
fab56fc5
LP
3075 return NULL;
3076
3077 STRV_FOREACH(i, argv) {
c24eb49e
LP
3078
3079 /* If $FOO appears as single word, replace it by the split up variable */
b95cf362
LP
3080 if ((*i)[0] == '$' && (*i)[1] != '{') {
3081 char *e;
3082 char **w, **m;
3083 unsigned q;
c24eb49e 3084
4d1a6904
LP
3085 e = strv_env_get(env, *i+1);
3086 if (e) {
c24eb49e
LP
3087
3088 if (!(m = strv_split_quoted(e))) {
3089 r[k] = NULL;
3090 strv_free(r);
3091 return NULL;
3092 }
b95cf362
LP
3093 } else
3094 m = NULL;
c24eb49e 3095
b95cf362
LP
3096 q = strv_length(m);
3097 l = l + q - 1;
c24eb49e 3098
b95cf362
LP
3099 if (!(w = realloc(r, sizeof(char*) * (l+1)))) {
3100 r[k] = NULL;
3101 strv_free(r);
3102 strv_free(m);
3103 return NULL;
3104 }
c24eb49e 3105
b95cf362
LP
3106 r = w;
3107 if (m) {
c24eb49e
LP
3108 memcpy(r + k, m, q * sizeof(char*));
3109 free(m);
c24eb49e 3110 }
b95cf362
LP
3111
3112 k += q;
3113 continue;
c24eb49e
LP
3114 }
3115
3116 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
fab56fc5
LP
3117 if (!(r[k++] = replace_env(*i, env))) {
3118 strv_free(r);
3119 return NULL;
3120 }
3121 }
3122
3123 r[k] = NULL;
3124 return r;
3125}
3126
81beb750 3127int fd_columns(int fd) {
b92bea5d 3128 struct winsize ws = {};
81beb750
LP
3129
3130 if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
3131 return -errno;
3132
3133 if (ws.ws_col <= 0)
3134 return -EIO;
3135
3136 return ws.ws_col;
3137}
3138
28917d7d 3139unsigned columns(void) {
fa776d8e 3140 const char *e;
7009eec2 3141 int c;
fa776d8e 3142
28917d7d
LP
3143 if (_likely_(cached_columns > 0))
3144 return cached_columns;
11f96fac 3145
28917d7d
LP
3146 c = 0;
3147 e = getenv("COLUMNS");
3148 if (e)
7009eec2 3149 safe_atoi(e, &c);
fa776d8e 3150
28917d7d
LP
3151 if (c <= 0)
3152 c = fd_columns(STDOUT_FILENO);
fa776d8e 3153
28917d7d
LP
3154 if (c <= 0)
3155 c = 80;
11f96fac 3156
28917d7d
LP
3157 cached_columns = c;
3158 return c;
11f96fac
ZJS
3159}
3160
8f2d43a0 3161int fd_lines(int fd) {
b92bea5d 3162 struct winsize ws = {};
8f2d43a0
LP
3163
3164 if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
3165 return -errno;
3166
3167 if (ws.ws_row <= 0)
3168 return -EIO;
3169
3170 return ws.ws_row;
3171}
3172
3173unsigned lines(void) {
8f2d43a0 3174 const char *e;
ed757c0c 3175 unsigned l;
8f2d43a0 3176
ed757c0c
LP
3177 if (_likely_(cached_lines > 0))
3178 return cached_lines;
8f2d43a0 3179
ed757c0c 3180 l = 0;
8f2d43a0
LP
3181 e = getenv("LINES");
3182 if (e)
ed757c0c 3183 safe_atou(e, &l);
8f2d43a0 3184
ed757c0c
LP
3185 if (l <= 0)
3186 l = fd_lines(STDOUT_FILENO);
8f2d43a0 3187
ed757c0c
LP
3188 if (l <= 0)
3189 l = 24;
8f2d43a0 3190
ed757c0c
LP
3191 cached_lines = l;
3192 return cached_lines;
3193}
3194
3195/* intended to be used as a SIGWINCH sighandler */
3196void columns_lines_cache_reset(int signum) {
3197 cached_columns = 0;
3198 cached_lines = 0;
3199}
3200
3201bool on_tty(void) {
3202 static int cached_on_tty = -1;
3203
3204 if (_unlikely_(cached_on_tty < 0))
3205 cached_on_tty = isatty(STDOUT_FILENO) > 0;
3206
3207 return cached_on_tty;
8f2d43a0
LP
3208}
3209
b4f10a5e 3210int running_in_chroot(void) {
b92bea5d 3211 struct stat a = {}, b = {};
b4f10a5e
LP
3212
3213 /* Only works as root */
b4f10a5e
LP
3214 if (stat("/proc/1/root", &a) < 0)
3215 return -errno;
3216
3217 if (stat("/", &b) < 0)
3218 return -errno;
3219
3220 return
3221 a.st_dev != b.st_dev ||
3222 a.st_ino != b.st_ino;
3223}
3224
f405e86d 3225static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
72f59706 3226 size_t x;
8fe914ec
LP
3227 char *r;
3228
3229 assert(s);
3230 assert(percent <= 100);
72f59706 3231 assert(new_length >= 3);
8fe914ec 3232
72f59706
LP
3233 if (old_length <= 3 || old_length <= new_length)
3234 return strndup(s, old_length);
8fe914ec 3235
72f59706
LP
3236 r = new0(char, new_length+1);
3237 if (!r)
a6f0104a 3238 return NULL;
8fe914ec 3239
72f59706 3240 x = (new_length * percent) / 100;
8fe914ec 3241
72f59706
LP
3242 if (x > new_length - 3)
3243 x = new_length - 3;
8fe914ec
LP
3244
3245 memcpy(r, s, x);
3246 r[x] = '.';
3247 r[x+1] = '.';
3248 r[x+2] = '.';
3249 memcpy(r + x + 3,
72f59706
LP
3250 s + old_length - (new_length - x - 3),
3251 new_length - x - 3);
8fe914ec
LP
3252
3253 return r;
3254}
3255
f405e86d
SL
3256char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
3257 size_t x;
3258 char *e;
3259 const char *i, *j;
3260 unsigned k, len, len2;
3261
3262 assert(s);
3263 assert(percent <= 100);
3264 assert(new_length >= 3);
3265
3266 /* if no multibyte characters use ascii_ellipsize_mem for speed */
3267 if (ascii_is_valid(s))
3268 return ascii_ellipsize_mem(s, old_length, new_length, percent);
3269
3270 if (old_length <= 3 || old_length <= new_length)
3271 return strndup(s, old_length);
3272
3273 x = (new_length * percent) / 100;
3274
3275 if (x > new_length - 3)
3276 x = new_length - 3;
3277
3278 k = 0;
3279 for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) {
3280 int c;
3281
3282 c = utf8_encoded_to_unichar(i);
3283 if (c < 0)
3284 return NULL;
3285 k += unichar_iswide(c) ? 2 : 1;
3286 }
3287
3288 if (k > x) /* last character was wide and went over quota */
3289 x ++;
3290
3291 for (j = s + old_length; k < new_length && j > i; ) {
3292 int c;
3293
3294 j = utf8_prev_char(j);
3295 c = utf8_encoded_to_unichar(j);
3296 if (c < 0)
3297 return NULL;
3298 k += unichar_iswide(c) ? 2 : 1;
3299 }
3300 assert(i <= j);
3301
3302 /* we don't actually need to ellipsize */
3303 if (i == j)
3304 return memdup(s, old_length + 1);
3305
3306 /* make space for ellipsis */
3307 j = utf8_next_char(j);
3308
3309 len = i - s;
3310 len2 = s + old_length - j;
3311 e = new(char, len + 3 + len2 + 1);
3312 if (!e)
3313 return NULL;
3314
3315 /*
3316 printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n",
3317 old_length, new_length, x, len, len2, k);
3318 */
3319
3320 memcpy(e, s, len);
3321 e[len] = 0xe2; /* tri-dot ellipsis: … */
3322 e[len + 1] = 0x80;
3323 e[len + 2] = 0xa6;
3324
3325 memcpy(e + len + 3, j, len2 + 1);
3326
3327 return e;
3328}
3329
72f59706
LP
3330char *ellipsize(const char *s, size_t length, unsigned percent) {
3331 return ellipsize_mem(s, strlen(s), length, percent);
3332}
3333
f6144808
LP
3334int touch(const char *path) {
3335 int fd;
3336
3337 assert(path);
3338
73836c5c
LP
3339 /* This just opens the file for writing, ensuring it
3340 * exists. It doesn't call utimensat() the way /usr/bin/touch
3341 * does it. */
3342
3343 fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0644);
3344 if (fd < 0)
f6144808
LP
3345 return -errno;
3346
3347 close_nointr_nofail(fd);
3348 return 0;
3349}
afea26ad 3350
97c4a07d 3351char *unquote(const char *s, const char* quotes) {
11ce3427
LP
3352 size_t l;
3353 assert(s);
3354
73836c5c
LP
3355 /* This is rather stupid, simply removes the heading and
3356 * trailing quotes if there is one. Doesn't care about
57f30678
LP
3357 * escaping or anything. We should make this smarter one
3358 * day...*/
73836c5c 3359
31ed59c5
LP
3360 l = strlen(s);
3361 if (l < 2)
11ce3427
LP
3362 return strdup(s);
3363
97c4a07d 3364 if (strchr(quotes, s[0]) && s[l-1] == s[0])
11ce3427
LP
3365 return strndup(s+1, l-2);
3366
3367 return strdup(s);
3368}
3369
5f7c426e 3370char *normalize_env_assignment(const char *s) {
57f30678
LP
3371 _cleanup_free_ char *name = NULL, *value = NULL, *p = NULL;
3372 char *eq, *r;
5f7c426e 3373
57f30678
LP
3374 eq = strchr(s, '=');
3375 if (!eq) {
3376 char *t;
5f7c426e 3377
57f30678
LP
3378 r = strdup(s);
3379 if (!r)
5f7c426e
LP
3380 return NULL;
3381
57f30678
LP
3382 t = strstrip(r);
3383 if (t == r)
3384 return r;
3385
3386 memmove(r, t, strlen(t) + 1);
3387 return r;
5f7c426e
LP
3388 }
3389
57f30678
LP
3390 name = strndup(s, eq - s);
3391 if (!name)
5f7c426e
LP
3392 return NULL;
3393
57f30678
LP
3394 p = strdup(eq + 1);
3395 if (!p)
5f7c426e 3396 return NULL;
5f7c426e
LP
3397
3398 value = unquote(strstrip(p), QUOTES);
57f30678 3399 if (!value)
5f7c426e 3400 return NULL;
5f7c426e 3401
57f30678 3402 if (asprintf(&r, "%s=%s", strstrip(name), value) < 0)
5f7c426e
LP
3403 r = NULL;
3404
5f7c426e
LP
3405 return r;
3406}
3407
8e12a6ae 3408int wait_for_terminate(pid_t pid, siginfo_t *status) {
1968a360
LP
3409 siginfo_t dummy;
3410
2e78aa99 3411 assert(pid >= 1);
1968a360
LP
3412
3413 if (!status)
3414 status = &dummy;
2e78aa99
LP
3415
3416 for (;;) {
8e12a6ae
LP
3417 zero(*status);
3418
3419 if (waitid(P_PID, pid, status, WEXITED) < 0) {
2e78aa99
LP
3420
3421 if (errno == EINTR)
3422 continue;
3423
3424 return -errno;
3425 }
3426
3427 return 0;
3428 }
3429}
3430
97c4a07d
LP
3431int wait_for_terminate_and_warn(const char *name, pid_t pid) {
3432 int r;
3433 siginfo_t status;
3434
3435 assert(name);
3436 assert(pid > 1);
3437
d87be9b0
LP
3438 r = wait_for_terminate(pid, &status);
3439 if (r < 0) {
97c4a07d
LP
3440 log_warning("Failed to wait for %s: %s", name, strerror(-r));
3441 return r;
3442 }
3443
3444 if (status.si_code == CLD_EXITED) {
3445 if (status.si_status != 0) {
3446 log_warning("%s failed with error code %i.", name, status.si_status);
0a27cf3f 3447 return status.si_status;
97c4a07d
LP
3448 }
3449
3450 log_debug("%s succeeded.", name);
3451 return 0;
3452
3453 } else if (status.si_code == CLD_KILLED ||
3454 status.si_code == CLD_DUMPED) {
3455
3456 log_warning("%s terminated by signal %s.", name, signal_to_string(status.si_status));
3457 return -EPROTO;
3458 }
3459
3460 log_warning("%s failed due to unknown reason.", name);
3461 return -EPROTO;
97c4a07d
LP
3462}
3463
919ce0b7 3464noreturn void freeze(void) {
720ce21d
LP
3465
3466 /* Make sure nobody waits for us on a socket anymore */
3467 close_all_fds(NULL, 0);
3468
c29597a1
LP
3469 sync();
3470
3c14d26c
LP
3471 for (;;)
3472 pause();
3473}
3474
00dc5d76
LP
3475bool null_or_empty(struct stat *st) {
3476 assert(st);
3477
3478 if (S_ISREG(st->st_mode) && st->st_size <= 0)
3479 return true;
3480
c8f26f42 3481 if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
00dc5d76
LP
3482 return true;
3483
3484 return false;
3485}
3486
83096483
LP
3487int null_or_empty_path(const char *fn) {
3488 struct stat st;
3489
3490 assert(fn);
3491
3492 if (stat(fn, &st) < 0)
3493 return -errno;
3494
3495 return null_or_empty(&st);
3496}
3497
a247755d 3498DIR *xopendirat(int fd, const char *name, int flags) {
c4731d11
LP
3499 int nfd;
3500 DIR *d;
3501
dd94c17e
LP
3502 assert(!(flags & O_CREAT));
3503
3504 nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
73836c5c 3505 if (nfd < 0)
c4731d11
LP
3506 return NULL;
3507
73836c5c
LP
3508 d = fdopendir(nfd);
3509 if (!d) {
c4731d11
LP
3510 close_nointr_nofail(nfd);
3511 return NULL;
3512 }
3513
3514 return d;
3b63d2d3
LP
3515}
3516
8a0867d6
LP
3517int signal_from_string_try_harder(const char *s) {
3518 int signo;
3519 assert(s);
3520
73836c5c
LP
3521 signo = signal_from_string(s);
3522 if (signo <= 0)
8a0867d6
LP
3523 if (startswith(s, "SIG"))
3524 return signal_from_string(s+3);
3525
3526 return signo;
3527}
3528
383182b5 3529static char *tag_to_udev_node(const char *tagvalue, const char *by) {
22f5f628
DR
3530 _cleanup_free_ char *t = NULL, *u = NULL;
3531 char *dn;
3532 size_t enc_len;
e23a0ce8 3533
383182b5
DR
3534 u = unquote(tagvalue, "\"\'");
3535 if (u == NULL)
3536 return NULL;
e23a0ce8 3537
1d5989fd 3538 enc_len = strlen(u) * 4 + 1;
22f5f628 3539 t = new(char, enc_len);
383182b5
DR
3540 if (t == NULL)
3541 return NULL;
e23a0ce8 3542
8f6ce71f 3543 if (encode_devnode_name(u, t, enc_len) < 0)
22f5f628 3544 return NULL;
e23a0ce8 3545
22f5f628 3546 if (asprintf(&dn, "/dev/disk/by-%s/%s", by, t) < 0)
383182b5 3547 return NULL;
e23a0ce8 3548
383182b5
DR
3549 return dn;
3550}
e23a0ce8 3551
383182b5 3552char *fstab_node_to_udev_node(const char *p) {
faa368e3
LP
3553 assert(p);
3554
383182b5
DR
3555 if (startswith(p, "LABEL="))
3556 return tag_to_udev_node(p+6, "label");
e23a0ce8 3557
383182b5
DR
3558 if (startswith(p, "UUID="))
3559 return tag_to_udev_node(p+5, "uuid");
e23a0ce8 3560
84cc2abf
DR
3561 if (startswith(p, "PARTUUID="))
3562 return tag_to_udev_node(p+9, "partuuid");
3563
3564 if (startswith(p, "PARTLABEL="))
3565 return tag_to_udev_node(p+10, "partlabel");
3566
e23a0ce8
LP
3567 return strdup(p);
3568}
3569
f212ac12
LP
3570bool tty_is_vc(const char *tty) {
3571 assert(tty);
3572
3573 if (startswith(tty, "/dev/"))
3574 tty += 5;
3575
98a28fef
LP
3576 return vtnr_from_tty(tty) >= 0;
3577}
3578
d1122ad5
LP
3579bool tty_is_console(const char *tty) {
3580 assert(tty);
3581
3582 if (startswith(tty, "/dev/"))
3583 tty += 5;
3584
3585 return streq(tty, "console");
3586}
3587
98a28fef
LP
3588int vtnr_from_tty(const char *tty) {
3589 int i, r;
3590
3591 assert(tty);
3592
3593 if (startswith(tty, "/dev/"))
3594 tty += 5;
3595
3596 if (!startswith(tty, "tty") )
3597 return -EINVAL;
3598
3599 if (tty[3] < '0' || tty[3] > '9')
3600 return -EINVAL;
3601
3602 r = safe_atoi(tty+3, &i);
3603 if (r < 0)
3604 return r;
3605
3606 if (i < 0 || i > 63)
3607 return -EINVAL;
3608
3609 return i;
f212ac12
LP
3610}
3611
21baf21a
MS
3612char *resolve_dev_console(char **active) {
3613 char *tty;
3614
3615 /* Resolve where /dev/console is pointing to, if /sys is actually ours
3616 * (i.e. not read-only-mounted which is a sign for container setups) */
3617
3618 if (path_is_read_only_fs("/sys") > 0)
3619 return NULL;
3620
3621 if (read_one_line_file("/sys/class/tty/console/active", active) < 0)
3622 return NULL;
3623
3624 /* If multiple log outputs are configured the last one is what
3625 * /dev/console points to */
3626 tty = strrchr(*active, ' ');
3627 if (tty)
3628 tty++;
3629 else
3630 tty = *active;
3631
8aa5429a
OB
3632 if (streq(tty, "tty0")) {
3633 char *tmp;
3634
3635 /* Get the active VC (e.g. tty1) */
3636 if (read_one_line_file("/sys/class/tty/tty0/active", &tmp) >= 0) {
3637 free(*active);
3638 tty = *active = tmp;
3639 }
3640 }
3641
21baf21a
MS
3642 return tty;
3643}
3644
3043935f 3645bool tty_is_vc_resolve(const char *tty) {
9588bc32 3646 _cleanup_free_ char *active = NULL;
3030ccd7 3647
e3aa71c3
LP
3648 assert(tty);
3649
3650 if (startswith(tty, "/dev/"))
3651 tty += 5;
3652
21baf21a
MS
3653 if (streq(tty, "console")) {
3654 tty = resolve_dev_console(&active);
3655 if (!tty)
3656 return false;
3657 }
3030ccd7 3658
9588bc32 3659 return tty_is_vc(tty);
3043935f
LP
3660}
3661
3662const char *default_term_for_tty(const char *tty) {
3663 assert(tty);
3664
acda6a05 3665 return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt102";
e3aa71c3
LP
3666}
3667
87d2c1ff 3668bool dirent_is_file(const struct dirent *de) {
fb19a739
LP
3669 assert(de);
3670
3671 if (ignore_file(de->d_name))
3672 return false;
3673
3674 if (de->d_type != DT_REG &&
3675 de->d_type != DT_LNK &&
3676 de->d_type != DT_UNKNOWN)
3677 return false;
3678
3679 return true;
3680}
3681
87d2c1ff
LP
3682bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) {
3683 assert(de);
3684
a228a22f
LP
3685 if (de->d_type != DT_REG &&
3686 de->d_type != DT_LNK &&
3687 de->d_type != DT_UNKNOWN)
3688 return false;
3689
3690 if (ignore_file_allow_backup(de->d_name))
87d2c1ff
LP
3691 return false;
3692
3693 return endswith(de->d_name, suffix);
3694}
3695
83cc030f
LP
3696void execute_directory(const char *directory, DIR *d, char *argv[]) {
3697 DIR *_d = NULL;
3698 struct dirent *de;
3699 Hashmap *pids = NULL;
3700
3701 assert(directory);
3702
650001c6
JJ
3703 /* Executes all binaries in a directory in parallel and
3704 * waits for them to finish. */
83cc030f
LP
3705
3706 if (!d) {
3707 if (!(_d = opendir(directory))) {
3708
3709 if (errno == ENOENT)
3710 return;
3711
3712 log_error("Failed to enumerate directory %s: %m", directory);
3713 return;
3714 }
3715
3716 d = _d;
3717 }
3718
3719 if (!(pids = hashmap_new(trivial_hash_func, trivial_compare_func))) {
3720 log_error("Failed to allocate set.");
3721 goto finish;
3722 }
3723
3724 while ((de = readdir(d))) {
3725 char *path;
3726 pid_t pid;
3727 int k;
3728
fb19a739 3729 if (!dirent_is_file(de))
83cc030f
LP
3730 continue;
3731
3732 if (asprintf(&path, "%s/%s", directory, de->d_name) < 0) {
0d0f0c50 3733 log_oom();
83cc030f
LP
3734 continue;
3735 }
3736
3737 if ((pid = fork()) < 0) {
3738 log_error("Failed to fork: %m");
3739 free(path);
3740 continue;
3741 }
3742
3743 if (pid == 0) {
3744 char *_argv[2];
3745 /* Child */
3746
3747 if (!argv) {
3748 _argv[0] = path;
3749 _argv[1] = NULL;
3750 argv = _argv;
3751 } else
6edd7d0a 3752 argv[0] = path;
83cc030f
LP
3753
3754 execv(path, argv);
3755
3756 log_error("Failed to execute %s: %m", path);
3757 _exit(EXIT_FAILURE);
3758 }
3759
3760 log_debug("Spawned %s as %lu", path, (unsigned long) pid);
3761
3762 if ((k = hashmap_put(pids, UINT_TO_PTR(pid), path)) < 0) {
3763 log_error("Failed to add PID to set: %s", strerror(-k));
3764 free(path);
3765 }
3766 }
3767
3768 while (!hashmap_isempty(pids)) {
ec3f9b53 3769 pid_t pid = PTR_TO_UINT(hashmap_first_key(pids));
b92bea5d 3770 siginfo_t si = {};
83cc030f
LP
3771 char *path;
3772
ec3f9b53 3773 if (waitid(P_PID, pid, &si, WEXITED) < 0) {
83cc030f
LP
3774
3775 if (errno == EINTR)
3776 continue;
3777
3778 log_error("waitid() failed: %m");
3779 goto finish;
3780 }
3781
3782 if ((path = hashmap_remove(pids, UINT_TO_PTR(si.si_pid)))) {
96342de6 3783 if (!is_clean_exit(si.si_code, si.si_status, NULL)) {
83cc030f
LP
3784 if (si.si_code == CLD_EXITED)
3785 log_error("%s exited with exit status %i.", path, si.si_status);
3786 else
3787 log_error("%s terminated by signal %s.", path, signal_to_string(si.si_status));
3788 } else
3789 log_debug("%s exited successfully.", path);
3790
3791 free(path);
3792 }
3793 }
3794
3795finish:
3796 if (_d)
3797 closedir(_d);
3798
3799 if (pids)
3800 hashmap_free_free(pids);
3801}
3802
430c18ed
LP
3803int kill_and_sigcont(pid_t pid, int sig) {
3804 int r;
3805
3806 r = kill(pid, sig) < 0 ? -errno : 0;
3807
3808 if (r >= 0)
3809 kill(pid, SIGCONT);
3810
3811 return r;
3812}
3813
05feefe0
LP
3814bool nulstr_contains(const char*nulstr, const char *needle) {
3815 const char *i;
3816
3817 if (!nulstr)
3818 return false;
3819
3820 NULSTR_FOREACH(i, nulstr)
3821 if (streq(i, needle))
3822 return true;
3823
3824 return false;
3825}
3826
6faa1114 3827bool plymouth_running(void) {
9408a2d2 3828 return access("/run/plymouth/pid", F_OK) >= 0;
6faa1114
LP
3829}
3830
9beb3f4d
LP
3831char* strshorten(char *s, size_t l) {
3832 assert(s);
3833
3834 if (l < strlen(s))
3835 s[l] = 0;
3836
3837 return s;
3838}
3839
3840static bool hostname_valid_char(char c) {
3841 return
3842 (c >= 'a' && c <= 'z') ||
3843 (c >= 'A' && c <= 'Z') ||
3844 (c >= '0' && c <= '9') ||
3845 c == '-' ||
3846 c == '_' ||
3847 c == '.';
3848}
3849
3850bool hostname_is_valid(const char *s) {
3851 const char *p;
aa3c5cf8 3852 bool dot;
9beb3f4d
LP
3853
3854 if (isempty(s))
3855 return false;
3856
aa3c5cf8
LP
3857 for (p = s, dot = true; *p; p++) {
3858 if (*p == '.') {
3859 if (dot)
3860 return false;
3861
3862 dot = true;
3863 } else {
3864 if (!hostname_valid_char(*p))
3865 return false;
3866
3867 dot = false;
3868 }
3869 }
3870
3871 if (dot)
3872 return false;
9beb3f4d
LP
3873
3874 if (p-s > HOST_NAME_MAX)
3875 return false;
3876
3877 return true;
3878}
3879
e724b063 3880char* hostname_cleanup(char *s, bool lowercase) {
9beb3f4d 3881 char *p, *d;
cec4ead9
LP
3882 bool dot;
3883
3884 for (p = s, d = s, dot = true; *p; p++) {
3885 if (*p == '.') {
e724b063 3886 if (dot)
cec4ead9 3887 continue;
9beb3f4d 3888
e724b063 3889 *(d++) = '.';
cec4ead9 3890 dot = true;
e724b063
LP
3891 } else if (hostname_valid_char(*p)) {
3892 *(d++) = lowercase ? tolower(*p) : *p;
cec4ead9 3893 dot = false;
e724b063 3894 }
cec4ead9 3895
cec4ead9 3896 }
9beb3f4d 3897
e724b063
LP
3898 if (dot && d > s)
3899 d[-1] = 0;
3900 else
3901 *d = 0;
3902
9beb3f4d 3903 strshorten(s, HOST_NAME_MAX);
cec4ead9 3904
9beb3f4d
LP
3905 return s;
3906}
3907
1325aa42 3908int pipe_eof(int fd) {
1325aa42 3909 int r;
b92bea5d
ZJS
3910 struct pollfd pollfd = {
3911 .fd = fd,
3912 .events = POLLIN|POLLHUP,
3913 };
1325aa42
LP
3914
3915 r = poll(&pollfd, 1, 0);
3916 if (r < 0)
3917 return -errno;
3918
3919 if (r == 0)
3920 return 0;
3921
3922 return pollfd.revents & POLLHUP;
3923}
3924
8f2d43a0 3925int fd_wait_for_event(int fd, int event, usec_t t) {
df50185b 3926 int r;
b92bea5d
ZJS
3927 struct pollfd pollfd = {
3928 .fd = fd,
3929 .events = event,
3930 };
df50185b 3931
8f2d43a0 3932 r = poll(&pollfd, 1, t == (usec_t) -1 ? -1 : (int) (t / USEC_PER_MSEC));
df50185b
LP
3933 if (r < 0)
3934 return -errno;
3935
3936 if (r == 0)
3937 return 0;
3938
3939 return pollfd.revents;
3940}
3941
5a3ab509
LP
3942int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
3943 FILE *f;
3944 char *t;
3945 const char *fn;
3946 size_t k;
3947 int fd;
3948
3949 assert(path);
3950 assert(_f);
3951 assert(_temp_path);
3952
3953 t = new(char, strlen(path) + 1 + 6 + 1);
3954 if (!t)
3955 return -ENOMEM;
3956
2b6bf07d
ZJS
3957 fn = basename(path);
3958 k = fn - path;
5a3ab509
LP
3959 memcpy(t, path, k);
3960 t[k] = '.';
3961 stpcpy(stpcpy(t+k+1, fn), "XXXXXX");
3962
3963 fd = mkostemp(t, O_WRONLY|O_CLOEXEC);
3964 if (fd < 0) {
3965 free(t);
3966 return -errno;
3967 }
3968
3969 f = fdopen(fd, "we");
3970 if (!f) {
3971 unlink(t);
3972 free(t);
3973 return -errno;
3974 }
3975
3976 *_f = f;
3977 *_temp_path = t;
3978
3979 return 0;
3980}
3981
6ea832a2 3982int terminal_vhangup_fd(int fd) {
5a3ab509
LP
3983 assert(fd >= 0);
3984
6ea832a2
LP
3985 if (ioctl(fd, TIOCVHANGUP) < 0)
3986 return -errno;
3987
3988 return 0;
3989}
3990
3991int terminal_vhangup(const char *name) {
3992 int fd, r;
3993
3994 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
3995 if (fd < 0)
3996 return fd;
3997
3998 r = terminal_vhangup_fd(fd);
3999 close_nointr_nofail(fd);
4000
4001 return r;
4002}
4003
4004int vt_disallocate(const char *name) {
4005 int fd, r;
4006 unsigned u;
6ea832a2
LP
4007
4008 /* Deallocate the VT if possible. If not possible
4009 * (i.e. because it is the active one), at least clear it
4010 * entirely (including the scrollback buffer) */
4011
b83bc4e9
LP
4012 if (!startswith(name, "/dev/"))
4013 return -EINVAL;
4014
4015 if (!tty_is_vc(name)) {
4016 /* So this is not a VT. I guess we cannot deallocate
4017 * it then. But let's at least clear the screen */
4018
4019 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
4020 if (fd < 0)
4021 return fd;
4022
8585357a
LP
4023 loop_write(fd,
4024 "\033[r" /* clear scrolling region */
4025 "\033[H" /* move home */
4026 "\033[2J", /* clear screen */
4027 10, false);
b83bc4e9
LP
4028 close_nointr_nofail(fd);
4029
4030 return 0;
4031 }
6ea832a2
LP
4032
4033 if (!startswith(name, "/dev/tty"))
4034 return -EINVAL;
4035
4036 r = safe_atou(name+8, &u);
4037 if (r < 0)
4038 return r;
4039
4040 if (u <= 0)
b83bc4e9 4041 return -EINVAL;
6ea832a2 4042
b83bc4e9 4043 /* Try to deallocate */
6ea832a2
LP
4044 fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
4045 if (fd < 0)
4046 return fd;
4047
4048 r = ioctl(fd, VT_DISALLOCATE, u);
b83bc4e9 4049 close_nointr_nofail(fd);
6ea832a2 4050
b83bc4e9
LP
4051 if (r >= 0)
4052 return 0;
6ea832a2 4053
b83bc4e9 4054 if (errno != EBUSY)
6ea832a2 4055 return -errno;
6ea832a2 4056
b83bc4e9
LP
4057 /* Couldn't deallocate, so let's clear it fully with
4058 * scrollback */
4059 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
6ea832a2 4060 if (fd < 0)
b83bc4e9 4061 return fd;
6ea832a2 4062
8585357a
LP
4063 loop_write(fd,
4064 "\033[r" /* clear scrolling region */
4065 "\033[H" /* move home */
4066 "\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */
4067 10, false);
b83bc4e9 4068 close_nointr_nofail(fd);
6ea832a2 4069
b83bc4e9 4070 return 0;
6ea832a2
LP
4071}
4072
51045322
LP
4073int copy_file(const char *from, const char *to, int flags) {
4074 _cleanup_close_ int fdf = -1;
4075 int r, fdt;
34ca941c
LP
4076
4077 assert(from);
4078 assert(to);
4079
4080 fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY);
4081 if (fdf < 0)
4082 return -errno;
4083
51045322
LP
4084 fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0644);
4085 if (fdt < 0)
34ca941c 4086 return -errno;
34ca941c
LP
4087
4088 for (;;) {
4089 char buf[PIPE_BUF];
4090 ssize_t n, k;
4091
4092 n = read(fdf, buf, sizeof(buf));
4093 if (n < 0) {
4094 r = -errno;
4095
34ca941c
LP
4096 close_nointr(fdt);
4097 unlink(to);
4098
4099 return r;
4100 }
4101
4102 if (n == 0)
4103 break;
4104
4105 errno = 0;
4106 k = loop_write(fdt, buf, n, false);
4107 if (n != k) {
4108 r = k < 0 ? k : (errno ? -errno : -EIO);
4109
34ca941c 4110 close_nointr(fdt);
34ca941c 4111 unlink(to);
51045322 4112
34ca941c
LP
4113 return r;
4114 }
4115 }
4116
34ca941c
LP
4117 r = close_nointr(fdt);
4118
4119 if (r < 0) {
4120 unlink(to);
4121 return r;
4122 }
4123
4124 return 0;
4125}
4126
424a19f8
LP
4127int symlink_atomic(const char *from, const char *to) {
4128 char *x;
4129 _cleanup_free_ char *t;
34ca941c
LP
4130 const char *fn;
4131 size_t k;
9bf3b535 4132 uint64_t u;
34ca941c
LP
4133 unsigned i;
4134 int r;
4135
4136 assert(from);
4137 assert(to);
4138
4139 t = new(char, strlen(to) + 1 + 16 + 1);
4140 if (!t)
4141 return -ENOMEM;
4142
2b6bf07d 4143 fn = basename(to);
34ca941c
LP
4144 k = fn-to;
4145 memcpy(t, to, k);
4146 t[k] = '.';
4147 x = stpcpy(t+k+1, fn);
4148
9bf3b535 4149 u = random_u64();
34ca941c 4150 for (i = 0; i < 16; i++) {
9bf3b535
LP
4151 *(x++) = hexchar(u & 0xF);
4152 u >>= 4;
34ca941c
LP
4153 }
4154
4155 *x = 0;
4156
424a19f8
LP
4157 if (symlink(from, t) < 0)
4158 return -errno;
34ca941c
LP
4159
4160 if (rename(t, to) < 0) {
4161 r = -errno;
4162 unlink(t);
34ca941c
LP
4163 return r;
4164 }
4165
424a19f8 4166 return 0;
34ca941c
LP
4167}
4168
4d6d6518
LP
4169bool display_is_local(const char *display) {
4170 assert(display);
4171
4172 return
4173 display[0] == ':' &&
4174 display[1] >= '0' &&
4175 display[1] <= '9';
4176}
4177
4178int socket_from_display(const char *display, char **path) {
4179 size_t k;
4180 char *f, *c;
4181
4182 assert(display);
4183 assert(path);
4184
4185 if (!display_is_local(display))
4186 return -EINVAL;
4187
4188 k = strspn(display+1, "0123456789");
4189
4190 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
4191 if (!f)
4192 return -ENOMEM;
4193
4194 c = stpcpy(f, "/tmp/.X11-unix/X");
4195 memcpy(c, display+1, k);
4196 c[k] = 0;
4197
4198 *path = f;
4199
4200 return 0;
4201}
4202
d05c5031
LP
4203int get_user_creds(
4204 const char **username,
4205 uid_t *uid, gid_t *gid,
4206 const char **home,
4207 const char **shell) {
4208
1cccf435 4209 struct passwd *p;
ddd88763 4210 uid_t u;
1cccf435
MV
4211
4212 assert(username);
4213 assert(*username);
1cccf435
MV
4214
4215 /* We enforce some special rules for uid=0: in order to avoid
4216 * NSS lookups for root we hardcode its data. */
4217
4218 if (streq(*username, "root") || streq(*username, "0")) {
4219 *username = "root";
4b67834e
LP
4220
4221 if (uid)
4222 *uid = 0;
4223
4224 if (gid)
4225 *gid = 0;
4226
4227 if (home)
4228 *home = "/root";
d05c5031
LP
4229
4230 if (shell)
4231 *shell = "/bin/sh";
4232
1cccf435
MV
4233 return 0;
4234 }
4235
ddd88763 4236 if (parse_uid(*username, &u) >= 0) {
1cccf435 4237 errno = 0;
ddd88763 4238 p = getpwuid(u);
1cccf435
MV
4239
4240 /* If there are multiple users with the same id, make
4241 * sure to leave $USER to the configured value instead
4242 * of the first occurrence in the database. However if
4243 * the uid was configured by a numeric uid, then let's
4244 * pick the real username from /etc/passwd. */
4245 if (p)
4246 *username = p->pw_name;
4247 } else {
4248 errno = 0;
4249 p = getpwnam(*username);
4250 }
4251
4252 if (!p)
8333c77e 4253 return errno > 0 ? -errno : -ESRCH;
1cccf435 4254
4b67834e
LP
4255 if (uid)
4256 *uid = p->pw_uid;
4257
4258 if (gid)
4259 *gid = p->pw_gid;
4260
4261 if (home)
4262 *home = p->pw_dir;
4263
d05c5031
LP
4264 if (shell)
4265 *shell = p->pw_shell;
4266
4b67834e
LP
4267 return 0;
4268}
4269
59164be4
LP
4270char* uid_to_name(uid_t uid) {
4271 struct passwd *p;
4272 char *r;
4273
4274 if (uid == 0)
4275 return strdup("root");
4276
4277 p = getpwuid(uid);
4278 if (p)
4279 return strdup(p->pw_name);
4280
4281 if (asprintf(&r, "%lu", (unsigned long) uid) < 0)
4282 return NULL;
4283
4284 return r;
4285}
4286
4468addc
LP
4287char* gid_to_name(gid_t gid) {
4288 struct group *p;
4289 char *r;
4290
4291 if (gid == 0)
4292 return strdup("root");
4293
4294 p = getgrgid(gid);
4295 if (p)
4296 return strdup(p->gr_name);
4297
4298 if (asprintf(&r, "%lu", (unsigned long) gid) < 0)
4299 return NULL;
4300
4301 return r;
4302}
4303
4b67834e
LP
4304int get_group_creds(const char **groupname, gid_t *gid) {
4305 struct group *g;
4306 gid_t id;
4307
4308 assert(groupname);
4309
4310 /* We enforce some special rules for gid=0: in order to avoid
4311 * NSS lookups for root we hardcode its data. */
4312
4313 if (streq(*groupname, "root") || streq(*groupname, "0")) {
4314 *groupname = "root";
4315
4316 if (gid)
4317 *gid = 0;
4318
4319 return 0;
4320 }
4321
4322 if (parse_gid(*groupname, &id) >= 0) {
4323 errno = 0;
4324 g = getgrgid(id);
4325
4326 if (g)
4327 *groupname = g->gr_name;
4328 } else {
4329 errno = 0;
4330 g = getgrnam(*groupname);
4331 }
4332
4333 if (!g)
8333c77e 4334 return errno > 0 ? -errno : -ESRCH;
4b67834e
LP
4335
4336 if (gid)
4337 *gid = g->gr_gid;
4338
1cccf435
MV
4339 return 0;
4340}
4341
4468addc
LP
4342int in_gid(gid_t gid) {
4343 gid_t *gids;
43673799
LP
4344 int ngroups_max, r, i;
4345
43673799
LP
4346 if (getgid() == gid)
4347 return 1;
4348
4349 if (getegid() == gid)
4350 return 1;
4351
4352 ngroups_max = sysconf(_SC_NGROUPS_MAX);
4353 assert(ngroups_max > 0);
4354
4355 gids = alloca(sizeof(gid_t) * ngroups_max);
4356
4357 r = getgroups(ngroups_max, gids);
4358 if (r < 0)
4359 return -errno;
4360
4361 for (i = 0; i < r; i++)
4362 if (gids[i] == gid)
4363 return 1;
4364
4365 return 0;
4366}
4367
4468addc
LP
4368int in_group(const char *name) {
4369 int r;
4370 gid_t gid;
4371
4372 r = get_group_creds(&name, &gid);
4373 if (r < 0)
4374 return r;
4375
4376 return in_gid(gid);
4377}
4378
8092a428 4379int glob_exists(const char *path) {
7fd1b19b 4380 _cleanup_globfree_ glob_t g = {};
8d98da3f 4381 int k;
8092a428
LP
4382
4383 assert(path);
4384
8092a428
LP
4385 errno = 0;
4386 k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
4387
4388 if (k == GLOB_NOMATCH)
8d98da3f 4389 return 0;
8092a428 4390 else if (k == GLOB_NOSPACE)
8d98da3f 4391 return -ENOMEM;
8092a428 4392 else if (k == 0)
8d98da3f 4393 return !strv_isempty(g.gl_pathv);
8092a428 4394 else
8d98da3f
ZJS
4395 return errno ? -errno : -EIO;
4396}
8092a428 4397
8d98da3f
ZJS
4398int glob_extend(char ***strv, const char *path) {
4399 _cleanup_globfree_ glob_t g = {};
4400 int k;
4401 char **p;
4402
4403 errno = 0;
a8ccacf5 4404 k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
8d98da3f
ZJS
4405
4406 if (k == GLOB_NOMATCH)
4407 return -ENOENT;
4408 else if (k == GLOB_NOSPACE)
4409 return -ENOMEM;
4410 else if (k != 0 || strv_isempty(g.gl_pathv))
4411 return errno ? -errno : -EIO;
4412
4413 STRV_FOREACH(p, g.gl_pathv) {
4414 k = strv_extend(strv, *p);
4415 if (k < 0)
4416 break;
4417 }
4418
4419 return k;
8092a428
LP
4420}
4421
83096483
LP
4422int dirent_ensure_type(DIR *d, struct dirent *de) {
4423 struct stat st;
4424
4425 assert(d);
4426 assert(de);
4427
4428 if (de->d_type != DT_UNKNOWN)
4429 return 0;
4430
4431 if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
4432 return -errno;
4433
4434 de->d_type =
4435 S_ISREG(st.st_mode) ? DT_REG :
4436 S_ISDIR(st.st_mode) ? DT_DIR :
4437 S_ISLNK(st.st_mode) ? DT_LNK :
4438 S_ISFIFO(st.st_mode) ? DT_FIFO :
4439 S_ISSOCK(st.st_mode) ? DT_SOCK :
4440 S_ISCHR(st.st_mode) ? DT_CHR :
4441 S_ISBLK(st.st_mode) ? DT_BLK :
4442 DT_UNKNOWN;
4443
4444 return 0;
4445}
4446
4447int in_search_path(const char *path, char **search) {
893fa014
ZJS
4448 char **i;
4449 _cleanup_free_ char *parent = NULL;
83096483
LP
4450 int r;
4451
9eb977db 4452 r = path_get_parent(path, &parent);
83096483
LP
4453 if (r < 0)
4454 return r;
4455
893fa014
ZJS
4456 STRV_FOREACH(i, search)
4457 if (path_equal(parent, *i))
4458 return 1;
83096483 4459
893fa014 4460 return 0;
83096483
LP
4461}
4462
034a2a52 4463int get_files_in_directory(const char *path, char ***list) {
893fa014
ZJS
4464 _cleanup_closedir_ DIR *d = NULL;
4465 size_t bufsize = 0, n = 0;
4466 _cleanup_strv_free_ char **l = NULL;
034a2a52
LP
4467
4468 assert(path);
d60ef526
LP
4469
4470 /* Returns all files in a directory in *list, and the number
4471 * of files as return value. If list is NULL returns only the
893fa014 4472 * number. */
034a2a52
LP
4473
4474 d = opendir(path);
8ea913b2
LP
4475 if (!d)
4476 return -errno;
4477
034a2a52 4478 for (;;) {
7d5e9c0f 4479 struct dirent *de;
034a2a52 4480
3fd11280
FW
4481 errno = 0;
4482 de = readdir(d);
4483 if (!de && errno != 0)
4484 return -errno;
034a2a52
LP
4485 if (!de)
4486 break;
4487
4488 dirent_ensure_type(d, de);
4489
4490 if (!dirent_is_file(de))
4491 continue;
4492
d60ef526 4493 if (list) {
893fa014
ZJS
4494 /* one extra slot is needed for the terminating NULL */
4495 if (!GREEDY_REALLOC(l, bufsize, n + 2))
4496 return -ENOMEM;
034a2a52 4497
893fa014
ZJS
4498 l[n] = strdup(de->d_name);
4499 if (!l[n])
4500 return -ENOMEM;
034a2a52 4501
893fa014 4502 l[++n] = NULL;
d60ef526 4503 } else
893fa014 4504 n++;
034a2a52
LP
4505 }
4506
893fa014
ZJS
4507 if (list) {
4508 *list = l;
4509 l = NULL; /* avoid freeing */
4510 }
034a2a52 4511
893fa014 4512 return n;
034a2a52
LP
4513}
4514
b7def684 4515char *strjoin(const char *x, ...) {
911a4828
LP
4516 va_list ap;
4517 size_t l;
4518 char *r, *p;
4519
4520 va_start(ap, x);
4521
4522 if (x) {
4523 l = strlen(x);
4524
4525 for (;;) {
4526 const char *t;
040f18ea 4527 size_t n;
911a4828
LP
4528
4529 t = va_arg(ap, const char *);
4530 if (!t)
4531 break;
4532
040f18ea 4533 n = strlen(t);
e98055de
LN
4534 if (n > ((size_t) -1) - l) {
4535 va_end(ap);
040f18ea 4536 return NULL;
e98055de 4537 }
040f18ea
LP
4538
4539 l += n;
911a4828
LP
4540 }
4541 } else
4542 l = 0;
4543
4544 va_end(ap);
4545
4546 r = new(char, l+1);
4547 if (!r)
4548 return NULL;
4549
4550 if (x) {
4551 p = stpcpy(r, x);
4552
4553 va_start(ap, x);
4554
4555 for (;;) {
4556 const char *t;
4557
4558 t = va_arg(ap, const char *);
4559 if (!t)
4560 break;
4561
4562 p = stpcpy(p, t);
4563 }
8ea913b2
LP
4564
4565 va_end(ap);
911a4828
LP
4566 } else
4567 r[0] = 0;
4568
4569 return r;
4570}
4571
b636465b 4572bool is_main_thread(void) {
ec202eae 4573 static thread_local int cached = 0;
b636465b
LP
4574
4575 if (_unlikely_(cached == 0))
4576 cached = getpid() == gettid() ? 1 : -1;
4577
4578 return cached > 0;
4579}
4580
94959f0f
LP
4581int block_get_whole_disk(dev_t d, dev_t *ret) {
4582 char *p, *s;
4583 int r;
4584 unsigned n, m;
4585
4586 assert(ret);
4587
4588 /* If it has a queue this is good enough for us */
4589 if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0)
4590 return -ENOMEM;
4591
4592 r = access(p, F_OK);
4593 free(p);
4594
4595 if (r >= 0) {
4596 *ret = d;
4597 return 0;
4598 }
4599
4600 /* If it is a partition find the originating device */
4601 if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0)
4602 return -ENOMEM;
4603
4604 r = access(p, F_OK);
4605 free(p);
4606
4607 if (r < 0)
4608 return -ENOENT;
4609
4610 /* Get parent dev_t */
4611 if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0)
4612 return -ENOMEM;
4613
4614 r = read_one_line_file(p, &s);
4615 free(p);
4616
4617 if (r < 0)
4618 return r;
4619
4620 r = sscanf(s, "%u:%u", &m, &n);
4621 free(s);
4622
4623 if (r != 2)
4624 return -EINVAL;
4625
4626 /* Only return this if it is really good enough for us. */
4627 if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0)
4628 return -ENOMEM;
4629
4630 r = access(p, F_OK);
4631 free(p);
4632
4633 if (r >= 0) {
4634 *ret = makedev(m, n);
4635 return 0;
4636 }
4637
4638 return -ENOENT;
4639}
4640
8d53b453 4641int file_is_priv_sticky(const char *p) {
ad293f5a
LP
4642 struct stat st;
4643
4644 assert(p);
4645
4646 if (lstat(p, &st) < 0)
4647 return -errno;
4648
4649 return
8d53b453 4650 (st.st_uid == 0 || st.st_uid == getuid()) &&
ad293f5a
LP
4651 (st.st_mode & S_ISVTX);
4652}
94959f0f 4653
f41607a6
LP
4654static const char *const ioprio_class_table[] = {
4655 [IOPRIO_CLASS_NONE] = "none",
4656 [IOPRIO_CLASS_RT] = "realtime",
4657 [IOPRIO_CLASS_BE] = "best-effort",
4658 [IOPRIO_CLASS_IDLE] = "idle"
4659};
4660
f8b69d1d 4661DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX);
f41607a6
LP
4662
4663static const char *const sigchld_code_table[] = {
4664 [CLD_EXITED] = "exited",
4665 [CLD_KILLED] = "killed",
4666 [CLD_DUMPED] = "dumped",
4667 [CLD_TRAPPED] = "trapped",
4668 [CLD_STOPPED] = "stopped",
4669 [CLD_CONTINUED] = "continued",
4670};
4671
4672DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
4673
4674static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = {
4675 [LOG_FAC(LOG_KERN)] = "kern",
4676 [LOG_FAC(LOG_USER)] = "user",
4677 [LOG_FAC(LOG_MAIL)] = "mail",
4678 [LOG_FAC(LOG_DAEMON)] = "daemon",
4679 [LOG_FAC(LOG_AUTH)] = "auth",
4680 [LOG_FAC(LOG_SYSLOG)] = "syslog",
4681 [LOG_FAC(LOG_LPR)] = "lpr",
4682 [LOG_FAC(LOG_NEWS)] = "news",
4683 [LOG_FAC(LOG_UUCP)] = "uucp",
4684 [LOG_FAC(LOG_CRON)] = "cron",
4685 [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
4686 [LOG_FAC(LOG_FTP)] = "ftp",
4687 [LOG_FAC(LOG_LOCAL0)] = "local0",
4688 [LOG_FAC(LOG_LOCAL1)] = "local1",
4689 [LOG_FAC(LOG_LOCAL2)] = "local2",
4690 [LOG_FAC(LOG_LOCAL3)] = "local3",
4691 [LOG_FAC(LOG_LOCAL4)] = "local4",
4692 [LOG_FAC(LOG_LOCAL5)] = "local5",
4693 [LOG_FAC(LOG_LOCAL6)] = "local6",
4694 [LOG_FAC(LOG_LOCAL7)] = "local7"
4695};
4696
f8b69d1d 4697DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0));
f41607a6
LP
4698
4699static const char *const log_level_table[] = {
4700 [LOG_EMERG] = "emerg",
4701 [LOG_ALERT] = "alert",
4702 [LOG_CRIT] = "crit",
4703 [LOG_ERR] = "err",
4704 [LOG_WARNING] = "warning",
4705 [LOG_NOTICE] = "notice",
4706 [LOG_INFO] = "info",
4707 [LOG_DEBUG] = "debug"
4708};
4709
f8b69d1d 4710DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG);
f41607a6
LP
4711
4712static const char* const sched_policy_table[] = {
4713 [SCHED_OTHER] = "other",
4714 [SCHED_BATCH] = "batch",
4715 [SCHED_IDLE] = "idle",
4716 [SCHED_FIFO] = "fifo",
4717 [SCHED_RR] = "rr"
4718};
4719
f8b69d1d 4720DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
f41607a6
LP
4721
4722static const char* const rlimit_table[] = {
4723 [RLIMIT_CPU] = "LimitCPU",
4724 [RLIMIT_FSIZE] = "LimitFSIZE",
4725 [RLIMIT_DATA] = "LimitDATA",
4726 [RLIMIT_STACK] = "LimitSTACK",
4727 [RLIMIT_CORE] = "LimitCORE",
4728 [RLIMIT_RSS] = "LimitRSS",
4729 [RLIMIT_NOFILE] = "LimitNOFILE",
4730 [RLIMIT_AS] = "LimitAS",
4731 [RLIMIT_NPROC] = "LimitNPROC",
4732 [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
4733 [RLIMIT_LOCKS] = "LimitLOCKS",
4734 [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
4735 [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
4736 [RLIMIT_NICE] = "LimitNICE",
4737 [RLIMIT_RTPRIO] = "LimitRTPRIO",
4738 [RLIMIT_RTTIME] = "LimitRTTIME"
4739};
4740
4741DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
4742
4743static const char* const ip_tos_table[] = {
4744 [IPTOS_LOWDELAY] = "low-delay",
4745 [IPTOS_THROUGHPUT] = "throughput",
4746 [IPTOS_RELIABILITY] = "reliability",
4747 [IPTOS_LOWCOST] = "low-cost",
4748};
4749
f8b69d1d 4750DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
f41607a6 4751
4e240ab0 4752static const char *const __signal_table[] = {
f41607a6
LP
4753 [SIGHUP] = "HUP",
4754 [SIGINT] = "INT",
4755 [SIGQUIT] = "QUIT",
4756 [SIGILL] = "ILL",
4757 [SIGTRAP] = "TRAP",
4758 [SIGABRT] = "ABRT",
4759 [SIGBUS] = "BUS",
4760 [SIGFPE] = "FPE",
4761 [SIGKILL] = "KILL",
4762 [SIGUSR1] = "USR1",
4763 [SIGSEGV] = "SEGV",
4764 [SIGUSR2] = "USR2",
4765 [SIGPIPE] = "PIPE",
4766 [SIGALRM] = "ALRM",
4767 [SIGTERM] = "TERM",
4768#ifdef SIGSTKFLT
4769 [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */
4770#endif
4771 [SIGCHLD] = "CHLD",
4772 [SIGCONT] = "CONT",
4773 [SIGSTOP] = "STOP",
4774 [SIGTSTP] = "TSTP",
4775 [SIGTTIN] = "TTIN",
4776 [SIGTTOU] = "TTOU",
4777 [SIGURG] = "URG",
4778 [SIGXCPU] = "XCPU",
4779 [SIGXFSZ] = "XFSZ",
4780 [SIGVTALRM] = "VTALRM",
4781 [SIGPROF] = "PROF",
4782 [SIGWINCH] = "WINCH",
4783 [SIGIO] = "IO",
4784 [SIGPWR] = "PWR",
4785 [SIGSYS] = "SYS"
4786};
4787
4e240ab0
MS
4788DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
4789
4790const char *signal_to_string(int signo) {
ec202eae 4791 static thread_local char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1];
4e240ab0
MS
4792 const char *name;
4793
4794 name = __signal_to_string(signo);
4795 if (name)
4796 return name;
4797
4798 if (signo >= SIGRTMIN && signo <= SIGRTMAX)
fa70beaa 4799 snprintf(buf, sizeof(buf), "RTMIN+%d", signo - SIGRTMIN);
4e240ab0 4800 else
fa70beaa
LP
4801 snprintf(buf, sizeof(buf), "%d", signo);
4802
4e240ab0
MS
4803 return buf;
4804}
4805
4806int signal_from_string(const char *s) {
4807 int signo;
4808 int offset = 0;
4809 unsigned u;
4810
040f18ea 4811 signo = __signal_from_string(s);
4e240ab0
MS
4812 if (signo > 0)
4813 return signo;
4814
4815 if (startswith(s, "RTMIN+")) {
4816 s += 6;
4817 offset = SIGRTMIN;
4818 }
4819 if (safe_atou(s, &u) >= 0) {
4820 signo = (int) u + offset;
4821 if (signo > 0 && signo < _NSIG)
4822 return signo;
4823 }
4824 return -1;
4825}
65457142
FC
4826
4827bool kexec_loaded(void) {
4828 bool loaded = false;
4829 char *s;
4830
4831 if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) {
4832 if (s[0] == '1')
4833 loaded = true;
4834 free(s);
4835 }
4836 return loaded;
4837}
fb9de93d
LP
4838
4839int strdup_or_null(const char *a, char **b) {
4840 char *c;
4841
4842 assert(b);
4843
4844 if (!a) {
4845 *b = NULL;
4846 return 0;
4847 }
4848
4849 c = strdup(a);
4850 if (!c)
4851 return -ENOMEM;
4852
4853 *b = c;
4854 return 0;
4855}
64685e0c 4856
87d2c1ff
LP
4857int prot_from_flags(int flags) {
4858
4859 switch (flags & O_ACCMODE) {
4860
4861 case O_RDONLY:
4862 return PROT_READ;
4863
4864 case O_WRONLY:
4865 return PROT_WRITE;
4866
4867 case O_RDWR:
4868 return PROT_READ|PROT_WRITE;
4869
4870 default:
4871 return -EINVAL;
4872 }
7c99e0c1 4873}
689b9a22 4874
babfc091 4875char *format_bytes(char *buf, size_t l, off_t t) {
c0f99c21 4876 unsigned i;
babfc091
LP
4877
4878 static const struct {
4879 const char *suffix;
4880 off_t factor;
4881 } table[] = {
32895bb3
LP
4882 { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
4883 { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
babfc091
LP
4884 { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
4885 { "G", 1024ULL*1024ULL*1024ULL },
4886 { "M", 1024ULL*1024ULL },
4887 { "K", 1024ULL },
4888 };
4889
4890 for (i = 0; i < ELEMENTSOF(table); i++) {
4891
4892 if (t >= table[i].factor) {
4893 snprintf(buf, l,
4894 "%llu.%llu%s",
4895 (unsigned long long) (t / table[i].factor),
4896 (unsigned long long) (((t*10ULL) / table[i].factor) % 10ULL),
4897 table[i].suffix);
4898
4899 goto finish;
4900 }
4901 }
4902
4903 snprintf(buf, l, "%lluB", (unsigned long long) t);
4904
4905finish:
4906 buf[l-1] = 0;
4907 return buf;
4908
4909}
55d7bfc1
LP
4910
4911void* memdup(const void *p, size_t l) {
4912 void *r;
4913
4914 assert(p);
4915
4916 r = malloc(l);
4917 if (!r)
4918 return NULL;
4919
4920 memcpy(r, p, l);
4921 return r;
4922}
bb99a35a
LP
4923
4924int fd_inc_sndbuf(int fd, size_t n) {
4925 int r, value;
4926 socklen_t l = sizeof(value);
4927
4928 r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
92d75ca4 4929 if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
bb99a35a
LP
4930 return 0;
4931
92d75ca4
LP
4932 /* If we have the privileges we will ignore the kernel limit. */
4933
bb99a35a 4934 value = (int) n;
92d75ca4
LP
4935 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
4936 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
4937 return -errno;
bb99a35a
LP
4938
4939 return 1;
4940}
4941
4942int fd_inc_rcvbuf(int fd, size_t n) {
4943 int r, value;
4944 socklen_t l = sizeof(value);
4945
4946 r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l);
92d75ca4 4947 if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
bb99a35a
LP
4948 return 0;
4949
92d75ca4 4950 /* If we have the privileges we will ignore the kernel limit. */
bb99a35a 4951
92d75ca4
LP
4952 value = (int) n;
4953 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0)
4954 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
4955 return -errno;
bb99a35a
LP
4956 return 1;
4957}
6bb92a16 4958
9bdc770c 4959int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
6bb92a16
LP
4960 pid_t parent_pid, agent_pid;
4961 int fd;
4962 bool stdout_is_tty, stderr_is_tty;
4963 unsigned n, i;
4964 va_list ap;
4965 char **l;
4966
4967 assert(pid);
4968 assert(path);
4969
4970 parent_pid = getpid();
4971
4972 /* Spawns a temporary TTY agent, making sure it goes away when
4973 * we go away */
4974
4975 agent_pid = fork();
4976 if (agent_pid < 0)
4977 return -errno;
4978
4979 if (agent_pid != 0) {
4980 *pid = agent_pid;
4981 return 0;
4982 }
4983
4984 /* In the child:
4985 *
4986 * Make sure the agent goes away when the parent dies */
4987 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
4988 _exit(EXIT_FAILURE);
4989
4990 /* Check whether our parent died before we were able
4991 * to set the death signal */
4992 if (getppid() != parent_pid)
4993 _exit(EXIT_SUCCESS);
4994
4995 /* Don't leak fds to the agent */
9bdc770c 4996 close_all_fds(except, n_except);
6bb92a16
LP
4997
4998 stdout_is_tty = isatty(STDOUT_FILENO);
4999 stderr_is_tty = isatty(STDERR_FILENO);
5000
5001 if (!stdout_is_tty || !stderr_is_tty) {
5002 /* Detach from stdout/stderr. and reopen
5003 * /dev/tty for them. This is important to
5004 * ensure that when systemctl is started via
5005 * popen() or a similar call that expects to
5006 * read EOF we actually do generate EOF and
5007 * not delay this indefinitely by because we
5008 * keep an unused copy of stdin around. */
5009 fd = open("/dev/tty", O_WRONLY);
5010 if (fd < 0) {
5011 log_error("Failed to open /dev/tty: %m");
5012 _exit(EXIT_FAILURE);
5013 }
5014
5015 if (!stdout_is_tty)
5016 dup2(fd, STDOUT_FILENO);
5017
5018 if (!stderr_is_tty)
5019 dup2(fd, STDERR_FILENO);
5020
5021 if (fd > 2)
5022 close(fd);
5023 }
5024
5025 /* Count arguments */
5026 va_start(ap, path);
5027 for (n = 0; va_arg(ap, char*); n++)
5028 ;
5029 va_end(ap);
5030
5031 /* Allocate strv */
5032 l = alloca(sizeof(char *) * (n + 1));
5033
5034 /* Fill in arguments */
5035 va_start(ap, path);
5036 for (i = 0; i <= n; i++)
5037 l[i] = va_arg(ap, char*);
5038 va_end(ap);
5039
5040 execv(path, l);
5041 _exit(EXIT_FAILURE);
5042}
68faf98c
LP
5043
5044int setrlimit_closest(int resource, const struct rlimit *rlim) {
5045 struct rlimit highest, fixed;
5046
5047 assert(rlim);
5048
5049 if (setrlimit(resource, rlim) >= 0)
5050 return 0;
5051
5052 if (errno != EPERM)
5053 return -errno;
5054
5055 /* So we failed to set the desired setrlimit, then let's try
5056 * to get as close as we can */
5057 assert_se(getrlimit(resource, &highest) == 0);
5058
5059 fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max);
5060 fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max);
5061
5062 if (setrlimit(resource, &fixed) < 0)
5063 return -errno;
5064
5065 return 0;
5066}
3d9a4122 5067
ab94af92 5068int getenv_for_pid(pid_t pid, const char *field, char **_value) {
49aa47c7
LP
5069 _cleanup_fclose_ FILE *f = NULL;
5070 char *value = NULL;
ab94af92 5071 int r;
ab94af92
LP
5072 bool done = false;
5073 size_t l;
49aa47c7 5074 const char *path;
ab94af92 5075
49aa47c7 5076 assert(pid >= 0);
ab94af92
LP
5077 assert(field);
5078 assert(_value);
5079
b68fa010 5080 path = procfs_file_alloca(pid, "environ");
ab94af92
LP
5081
5082 f = fopen(path, "re");
5083 if (!f)
5084 return -errno;
5085
5086 l = strlen(field);
5087 r = 0;
5088
5089 do {
5090 char line[LINE_MAX];
5091 unsigned i;
5092
5093 for (i = 0; i < sizeof(line)-1; i++) {
5094 int c;
5095
5096 c = getc(f);
5097 if (_unlikely_(c == EOF)) {
5098 done = true;
5099 break;
5100 } else if (c == 0)
5101 break;
5102
5103 line[i] = c;
5104 }
5105 line[i] = 0;
5106
5107 if (memcmp(line, field, l) == 0 && line[l] == '=') {
5108 value = strdup(line + l + 1);
49aa47c7
LP
5109 if (!value)
5110 return -ENOMEM;
ab94af92
LP
5111
5112 r = 1;
5113 break;
5114 }
5115
5116 } while (!done);
5117
49aa47c7 5118 *_value = value;
ab94af92
LP
5119 return r;
5120}
d889a206 5121
49dbfa7b
LP
5122bool is_valid_documentation_url(const char *url) {
5123 assert(url);
5124
5125 if (startswith(url, "http://") && url[7])
5126 return true;
5127
5128 if (startswith(url, "https://") && url[8])
5129 return true;
5130
5131 if (startswith(url, "file:") && url[5])
5132 return true;
5133
5134 if (startswith(url, "info:") && url[5])
5135 return true;
5136
5137 if (startswith(url, "man:") && url[4])
5138 return true;
5139
5140 return false;
5141}
9be346c9
HH
5142
5143bool in_initrd(void) {
73020ab2 5144 static int saved = -1;
825c6fe5 5145 struct statfs s;
8f33b5b8 5146
825c6fe5
LP
5147 if (saved >= 0)
5148 return saved;
5149
5150 /* We make two checks here:
5151 *
5152 * 1. the flag file /etc/initrd-release must exist
5153 * 2. the root file system must be a memory file system
5154 *
5155 * The second check is extra paranoia, since misdetecting an
5156 * initrd can have bad bad consequences due the initrd
5157 * emptying when transititioning to the main systemd.
5158 */
5159
5160 saved = access("/etc/initrd-release", F_OK) >= 0 &&
5161 statfs("/", &s) >= 0 &&
943aad8c 5162 is_temporary_fs(&s);
9be346c9 5163
8f33b5b8 5164 return saved;
9be346c9 5165}
069cfc85
LP
5166
5167void warn_melody(void) {
e67f47e5 5168 _cleanup_close_ int fd = -1;
069cfc85
LP
5169
5170 fd = open("/dev/console", O_WRONLY|O_CLOEXEC|O_NOCTTY);
5171 if (fd < 0)
5172 return;
5173
040f18ea 5174 /* Yeah, this is synchronous. Kinda sucks. But well... */
069cfc85
LP
5175
5176 ioctl(fd, KIOCSOUND, (int)(1193180/440));
5177 usleep(125*USEC_PER_MSEC);
5178
5179 ioctl(fd, KIOCSOUND, (int)(1193180/220));
5180 usleep(125*USEC_PER_MSEC);
5181
5182 ioctl(fd, KIOCSOUND, (int)(1193180/220));
5183 usleep(125*USEC_PER_MSEC);
5184
5185 ioctl(fd, KIOCSOUND, 0);
069cfc85 5186}
cd3bd60a
LP
5187
5188int make_console_stdio(void) {
5189 int fd, r;
5190
5191 /* Make /dev/console the controlling terminal and stdin/stdout/stderr */
5192
5193 fd = acquire_terminal("/dev/console", false, true, true, (usec_t) -1);
5194 if (fd < 0) {
5195 log_error("Failed to acquire terminal: %s", strerror(-fd));
5196 return fd;
5197 }
5198
5199 r = make_stdio(fd);
5200 if (r < 0) {
5201 log_error("Failed to duplicate terminal fd: %s", strerror(-r));
5202 return r;
5203 }
5204
5205 return 0;
5206}
7c5f152a
LP
5207
5208int get_home_dir(char **_h) {
2cfbd749 5209 struct passwd *p;
7c5f152a 5210 const char *e;
2cfbd749 5211 char *h;
7c5f152a 5212 uid_t u;
7c5f152a
LP
5213
5214 assert(_h);
5215
5216 /* Take the user specified one */
5217 e = getenv("HOME");
5218 if (e) {
5219 h = strdup(e);
5220 if (!h)
5221 return -ENOMEM;
5222
5223 *_h = h;
5224 return 0;
5225 }
5226
5227 /* Hardcode home directory for root to avoid NSS */
5228 u = getuid();
5229 if (u == 0) {
5230 h = strdup("/root");
5231 if (!h)
5232 return -ENOMEM;
5233
5234 *_h = h;
5235 return 0;
5236 }
5237
5238 /* Check the database... */
5239 errno = 0;
5240 p = getpwuid(u);
5241 if (!p)
bcb161b0 5242 return errno > 0 ? -errno : -ESRCH;
7c5f152a
LP
5243
5244 if (!path_is_absolute(p->pw_dir))
5245 return -EINVAL;
5246
5247 h = strdup(p->pw_dir);
5248 if (!h)
5249 return -ENOMEM;
5250
5251 *_h = h;
5252 return 0;
5253}
5254
2cfbd749
LP
5255int get_shell(char **_s) {
5256 struct passwd *p;
5257 const char *e;
5258 char *s;
5259 uid_t u;
5260
5261 assert(_s);
5262
5263 /* Take the user specified one */
5264 e = getenv("SHELL");
5265 if (e) {
5266 s = strdup(e);
5267 if (!s)
5268 return -ENOMEM;
5269
5270 *_s = s;
5271 return 0;
5272 }
5273
5274 /* Hardcode home directory for root to avoid NSS */
5275 u = getuid();
5276 if (u == 0) {
5277 s = strdup("/bin/sh");
5278 if (!s)
5279 return -ENOMEM;
5280
5281 *_s = s;
5282 return 0;
5283 }
5284
5285 /* Check the database... */
5286 errno = 0;
5287 p = getpwuid(u);
5288 if (!p)
5289 return errno > 0 ? -errno : -ESRCH;
5290
5291 if (!path_is_absolute(p->pw_shell))
5292 return -EINVAL;
5293
5294 s = strdup(p->pw_shell);
5295 if (!s)
5296 return -ENOMEM;
5297
5298 *_s = s;
5299 return 0;
5300}
5301
0b507b17
LP
5302bool filename_is_safe(const char *p) {
5303
5304 if (isempty(p))
5305 return false;
5306
5307 if (strchr(p, '/'))
5308 return false;
5309
5310 if (streq(p, "."))
5311 return false;
5312
5313 if (streq(p, ".."))
5314 return false;
5315
5316 if (strlen(p) > FILENAME_MAX)
5317 return false;
5318
5319 return true;
5320}
5321
5322bool string_is_safe(const char *p) {
5323 const char *t;
5324
5325 assert(p);
5326
5327 for (t = p; *t; t++) {
01539d6e 5328 if (*t > 0 && *t < ' ')
0b507b17
LP
5329 return false;
5330
011afa76 5331 if (strchr("\\\"\'", *t))
0b507b17
LP
5332 return false;
5333 }
5334
5335 return true;
5336}
cfbc22ab 5337
ac4c8d6d
ZJS
5338/**
5339 * Check if a string contains control characters.
5340 * Spaces and tabs are not considered control characters.
5341 */
4d1a6904
LP
5342bool string_has_cc(const char *p) {
5343 const char *t;
5344
5345 assert(p);
5346
5347 for (t = p; *t; t++)
da2620a5 5348 if (*t > 0 && *t < ' ' && *t != '\t')
4d1a6904
LP
5349 return true;
5350
5351 return false;
5352}
5353
e884315e
LP
5354bool path_is_safe(const char *p) {
5355
5356 if (isempty(p))
5357 return false;
5358
5359 if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
5360 return false;
5361
5362 if (strlen(p) > PATH_MAX)
5363 return false;
5364
5365 /* The following two checks are not really dangerous, but hey, they still are confusing */
5366 if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./"))
5367 return false;
5368
5369 if (strstr(p, "//"))
5370 return false;
5371
5372 return true;
5373}
5374
a9e12476
KS
5375/* hey glibc, APIs with callbacks without a user pointer are so useless */
5376void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
1c574591 5377 int (*compar) (const void *, const void *, void *), void *arg) {
a9e12476
KS
5378 size_t l, u, idx;
5379 const void *p;
5380 int comparison;
5381
5382 l = 0;
5383 u = nmemb;
5384 while (l < u) {
5385 idx = (l + u) / 2;
5386 p = (void *)(((const char *) base) + (idx * size));
5387 comparison = compar(key, p, arg);
5388 if (comparison < 0)
5389 u = idx;
5390 else if (comparison > 0)
5391 l = idx + 1;
5392 else
5393 return (void *)p;
5394 }
5395 return NULL;
5396}
09017585
MS
5397
5398bool is_locale_utf8(void) {
5399 const char *set;
5400 static int cached_answer = -1;
5401
5402 if (cached_answer >= 0)
5403 goto out;
5404
5405 if (!setlocale(LC_ALL, "")) {
5406 cached_answer = true;
5407 goto out;
5408 }
5409
5410 set = nl_langinfo(CODESET);
5411 if (!set) {
5412 cached_answer = true;
5413 goto out;
5414 }
5415
f168c273 5416 if (streq(set, "UTF-8")) {
fee79e01
HH
5417 cached_answer = true;
5418 goto out;
5419 }
5420
6cf2f1d9
HH
5421 /* For LC_CTYPE=="C" return true, because CTYPE is effectly
5422 * unset and everything can do to UTF-8 nowadays. */
fee79e01
HH
5423 set = setlocale(LC_CTYPE, NULL);
5424 if (!set) {
5425 cached_answer = true;
5426 goto out;
5427 }
5428
6cf2f1d9
HH
5429 /* Check result, but ignore the result if C was set
5430 * explicitly. */
5431 cached_answer =
5432 streq(set, "C") &&
5433 !getenv("LC_ALL") &&
5434 !getenv("LC_CTYPE") &&
5435 !getenv("LANG");
fee79e01 5436
09017585 5437out:
6cf2f1d9 5438 return (bool) cached_answer;
09017585 5439}
c339d977
MS
5440
5441const char *draw_special_char(DrawSpecialChar ch) {
5442 static const char *draw_table[2][_DRAW_SPECIAL_CHAR_MAX] = {
5443 /* UTF-8 */ {
45a5ff0d
MS
5444 [DRAW_TREE_VERT] = "\342\224\202 ", /* │ */
5445 [DRAW_TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */
5446 [DRAW_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */
55c0b89c 5447 [DRAW_TREE_SPACE] = " ", /* */
45a5ff0d 5448 [DRAW_TRIANGULAR_BULLET] = "\342\200\243 ", /* ‣ */
3deadb91 5449 [DRAW_BLACK_CIRCLE] = "\342\227\217 ", /* ● */
c339d977
MS
5450 },
5451 /* ASCII fallback */ {
45a5ff0d
MS
5452 [DRAW_TREE_VERT] = "| ",
5453 [DRAW_TREE_BRANCH] = "|-",
5454 [DRAW_TREE_RIGHT] = "`-",
55c0b89c 5455 [DRAW_TREE_SPACE] = " ",
45a5ff0d 5456 [DRAW_TRIANGULAR_BULLET] = "> ",
3deadb91 5457 [DRAW_BLACK_CIRCLE] = "* ",
c339d977
MS
5458 }
5459 };
5460
5461 return draw_table[!is_locale_utf8()][ch];
5462}
409bc9c3
LP
5463
5464char *strreplace(const char *text, const char *old_string, const char *new_string) {
5465 const char *f;
5466 char *t, *r;
5467 size_t l, old_len, new_len;
5468
5469 assert(text);
5470 assert(old_string);
5471 assert(new_string);
5472
5473 old_len = strlen(old_string);
5474 new_len = strlen(new_string);
5475
5476 l = strlen(text);
5477 r = new(char, l+1);
5478 if (!r)
5479 return NULL;
5480
5481 f = text;
5482 t = r;
5483 while (*f) {
5484 char *a;
5485 size_t d, nl;
5486
5487 if (!startswith(f, old_string)) {
5488 *(t++) = *(f++);
5489 continue;
5490 }
5491
5492 d = t - r;
5493 nl = l - old_len + new_len;
5494 a = realloc(r, nl + 1);
5495 if (!a)
5496 goto oom;
5497
5498 l = nl;
5499 r = a;
5500 t = r + d;
5501
5502 t = stpcpy(t, new_string);
5503 f += old_len;
5504 }
5505
5506 *t = 0;
5507 return r;
5508
5509oom:
5510 free(r);
5511 return NULL;
5512}
e8bc0ea2
LP
5513
5514char *strip_tab_ansi(char **ibuf, size_t *_isz) {
660ddc72 5515 const char *i, *begin = NULL;
e8bc0ea2
LP
5516 enum {
5517 STATE_OTHER,
5518 STATE_ESCAPE,
5519 STATE_BRACKET
5520 } state = STATE_OTHER;
5521 char *obuf = NULL;
5522 size_t osz = 0, isz;
5523 FILE *f;
5524
5525 assert(ibuf);
5526 assert(*ibuf);
5527
5528 /* Strips ANSI color and replaces TABs by 8 spaces */
5529
5530 isz = _isz ? *_isz : strlen(*ibuf);
5531
5532 f = open_memstream(&obuf, &osz);
5533 if (!f)
5534 return NULL;
5535
5536 for (i = *ibuf; i < *ibuf + isz + 1; i++) {
5537
5538 switch (state) {
5539
5540 case STATE_OTHER:
5541 if (i >= *ibuf + isz) /* EOT */
5542 break;
5543 else if (*i == '\x1B')
5544 state = STATE_ESCAPE;
5545 else if (*i == '\t')
5546 fputs(" ", f);
5547 else
5548 fputc(*i, f);
5549 break;
5550
5551 case STATE_ESCAPE:
5552 if (i >= *ibuf + isz) { /* EOT */
5553 fputc('\x1B', f);
5554 break;
5555 } else if (*i == '[') {
5556 state = STATE_BRACKET;
5557 begin = i + 1;
5558 } else {
5559 fputc('\x1B', f);
5560 fputc(*i, f);
5561 state = STATE_OTHER;
5562 }
5563
5564 break;
5565
5566 case STATE_BRACKET:
5567
5568 if (i >= *ibuf + isz || /* EOT */
5569 (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) {
5570 fputc('\x1B', f);
5571 fputc('[', f);
5572 state = STATE_OTHER;
5573 i = begin-1;
5574 } else if (*i == 'm')
5575 state = STATE_OTHER;
5576 break;
5577 }
5578 }
5579
5580 if (ferror(f)) {
5581 fclose(f);
5582 free(obuf);
5583 return NULL;
5584 }
5585
5586 fclose(f);
5587
5588 free(*ibuf);
5589 *ibuf = obuf;
5590
5591 if (_isz)
5592 *_isz = osz;
5593
5594 return obuf;
5595}
240dbaa4
LP
5596
5597int on_ac_power(void) {
5598 bool found_offline = false, found_online = false;
5599 _cleanup_closedir_ DIR *d = NULL;
5600
5601 d = opendir("/sys/class/power_supply");
5602 if (!d)
5603 return -errno;
5604
5605 for (;;) {
5606 struct dirent *de;
240dbaa4
LP
5607 _cleanup_close_ int fd = -1, device = -1;
5608 char contents[6];
5609 ssize_t n;
240dbaa4 5610
3fd11280
FW
5611 errno = 0;
5612 de = readdir(d);
5613 if (!de && errno != 0)
5614 return -errno;
240dbaa4
LP
5615
5616 if (!de)
5617 break;
5618
5619 if (ignore_file(de->d_name))
5620 continue;
5621
5622 device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
5623 if (device < 0) {
5624 if (errno == ENOENT || errno == ENOTDIR)
5625 continue;
5626
5627 return -errno;
5628 }
5629
5630 fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
5631 if (fd < 0) {
5632 if (errno == ENOENT)
5633 continue;
5634
5635 return -errno;
5636 }
5637
5638 n = read(fd, contents, sizeof(contents));
5639 if (n < 0)
5640 return -errno;
5641
5642 if (n != 6 || memcmp(contents, "Mains\n", 6))
5643 continue;
5644
5645 close_nointr_nofail(fd);
5646 fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
5647 if (fd < 0) {
5648 if (errno == ENOENT)
5649 continue;
5650
5651 return -errno;
5652 }
5653
5654 n = read(fd, contents, sizeof(contents));
5655 if (n < 0)
5656 return -errno;
5657
5658 if (n != 2 || contents[1] != '\n')
5659 return -EIO;
5660
5661 if (contents[0] == '1') {
5662 found_online = true;
5663 break;
5664 } else if (contents[0] == '0')
5665 found_offline = true;
5666 else
5667 return -EIO;
5668 }
5669
5670 return found_online || !found_offline;
5671}
fabe5c0e
LP
5672
5673static int search_and_fopen_internal(const char *path, const char *mode, char **search, FILE **_f) {
5674 char **i;
5675
5676 assert(path);
5677 assert(mode);
5678 assert(_f);
5679
5680 if (!path_strv_canonicalize_uniq(search))
5681 return -ENOMEM;
5682
5683 STRV_FOREACH(i, search) {
5684 _cleanup_free_ char *p = NULL;
5685 FILE *f;
5686
5687 p = strjoin(*i, "/", path, NULL);
5688 if (!p)
5689 return -ENOMEM;
5690
5691 f = fopen(p, mode);
5692 if (f) {
5693 *_f = f;
5694 return 0;
5695 }
5696
5697 if (errno != ENOENT)
5698 return -errno;
5699 }
5700
5701 return -ENOENT;
5702}
5703
5704int search_and_fopen(const char *path, const char *mode, const char **search, FILE **_f) {
5705 _cleanup_strv_free_ char **copy = NULL;
5706
5707 assert(path);
5708 assert(mode);
5709 assert(_f);
5710
5711 if (path_is_absolute(path)) {
5712 FILE *f;
5713
5714 f = fopen(path, mode);
5715 if (f) {
5716 *_f = f;
5717 return 0;
5718 }
5719
5720 return -errno;
5721 }
5722
5723 copy = strv_copy((char**) search);
5724 if (!copy)
5725 return -ENOMEM;
5726
5727 return search_and_fopen_internal(path, mode, copy, _f);
5728}
5729
5730int search_and_fopen_nulstr(const char *path, const char *mode, const char *search, FILE **_f) {
5731 _cleanup_strv_free_ char **s = NULL;
5732
5733 if (path_is_absolute(path)) {
5734 FILE *f;
5735
5736 f = fopen(path, mode);
5737 if (f) {
5738 *_f = f;
5739 return 0;
5740 }
5741
5742 return -errno;
5743 }
5744
5745 s = strv_split_nulstr(search);
5746 if (!s)
5747 return -ENOMEM;
5748
5749 return search_and_fopen_internal(path, mode, s, _f);
5750}
c17ec25e 5751
66e35261
LP
5752char *strextend(char **x, ...) {
5753 va_list ap;
5754 size_t f, l;
5755 char *r, *p;
5756
5757 assert(x);
5758
5759 l = f = *x ? strlen(*x) : 0;
5760
5761 va_start(ap, x);
5762 for (;;) {
5763 const char *t;
5764 size_t n;
5765
5766 t = va_arg(ap, const char *);
5767 if (!t)
5768 break;
5769
5770 n = strlen(t);
5771 if (n > ((size_t) -1) - l) {
5772 va_end(ap);
5773 return NULL;
5774 }
5775
5776 l += n;
5777 }
5778 va_end(ap);
5779
5780 r = realloc(*x, l+1);
5781 if (!r)
5782 return NULL;
5783
5784 p = r + f;
5785
5786 va_start(ap, x);
5787 for (;;) {
5788 const char *t;
5789
5790 t = va_arg(ap, const char *);
5791 if (!t)
5792 break;
5793
5794 p = stpcpy(p, t);
5795 }
5796 va_end(ap);
5797
5798 *p = 0;
5799 *x = r;
5800
5801 return r + l;
5802}
9a17484d
LP
5803
5804char *strrep(const char *s, unsigned n) {
5805 size_t l;
5806 char *r, *p;
5807 unsigned i;
5808
5809 assert(s);
5810
5811 l = strlen(s);
5812 p = r = malloc(l * n + 1);
5813 if (!r)
5814 return NULL;
5815
5816 for (i = 0; i < n; i++)
5817 p = stpcpy(p, s);
5818
5819 *p = 0;
5820 return r;
5821}
392d5b37
LP
5822
5823void* greedy_realloc(void **p, size_t *allocated, size_t need) {
5824 size_t a;
5825 void *q;
5826
98088803 5827 assert(p);
e93c33d4
SL
5828 assert(allocated);
5829
392d5b37
LP
5830 if (*allocated >= need)
5831 return *p;
5832
9607d947 5833 a = MAX(64u, need * 2);
98088803
LP
5834
5835 /* check for overflows */
5836 if (a < need)
5837 return NULL;
5838
392d5b37
LP
5839 q = realloc(*p, a);
5840 if (!q)
5841 return NULL;
5842
5843 *p = q;
5844 *allocated = a;
5845 return q;
5846}
aa96c6cb 5847
4545a231 5848void* greedy_realloc0(void **p, size_t *allocated, size_t need) {
98088803 5849 size_t prev;
4545a231
DH
5850 uint8_t *q;
5851
98088803
LP
5852 assert(p);
5853 assert(allocated);
5854
5855 prev = *allocated;
5856
4545a231
DH
5857 q = greedy_realloc(p, allocated, need);
5858 if (!q)
5859 return NULL;
5860
5861 if (*allocated > prev)
5862 memset(&q[prev], 0, *allocated - prev);
5863
5864 return q;
5865}
5866
aa96c6cb
LP
5867bool id128_is_valid(const char *s) {
5868 size_t i, l;
5869
5870 l = strlen(s);
5871 if (l == 32) {
5872
5873 /* Simple formatted 128bit hex string */
5874
5875 for (i = 0; i < l; i++) {
5876 char c = s[i];
5877
5878 if (!(c >= '0' && c <= '9') &&
5879 !(c >= 'a' && c <= 'z') &&
5880 !(c >= 'A' && c <= 'Z'))
5881 return false;
5882 }
5883
5884 } else if (l == 36) {
5885
5886 /* Formatted UUID */
5887
5888 for (i = 0; i < l; i++) {
5889 char c = s[i];
5890
5891 if ((i == 8 || i == 13 || i == 18 || i == 23)) {
5892 if (c != '-')
5893 return false;
5894 } else {
5895 if (!(c >= '0' && c <= '9') &&
5896 !(c >= 'a' && c <= 'z') &&
5897 !(c >= 'A' && c <= 'Z'))
5898 return false;
5899 }
5900 }
5901
5902 } else
5903 return false;
5904
5905 return true;
5906}
7085053a
DW
5907
5908void parse_user_at_host(char *arg, char **user, char **host) {
5909 assert(arg);
5910 assert(user);
5911 assert(host);
5912
5913 *host = strchr(arg, '@');
5914 if (*host == NULL)
5915 *host = arg;
5916 else {
5917 *host[0]++ = '\0';
5918 *user = arg;
5919 }
5920}
d4ac85c6
LP
5921
5922int split_pair(const char *s, const char *sep, char **l, char **r) {
5923 char *x, *a, *b;
5924
5925 assert(s);
5926 assert(sep);
5927 assert(l);
5928 assert(r);
5929
5930 if (isempty(sep))
5931 return -EINVAL;
5932
5933 x = strstr(s, sep);
5934 if (!x)
5935 return -EINVAL;
5936
5937 a = strndup(s, x - s);
5938 if (!a)
5939 return -ENOMEM;
5940
5941 b = strdup(x + strlen(sep));
5942 if (!b) {
5943 free(a);
5944 return -ENOMEM;
5945 }
5946
5947 *l = a;
5948 *r = b;
5949
5950 return 0;
5951}
295edddf 5952
74df0fca 5953int shall_restore_state(void) {
295edddf
TG
5954 _cleanup_free_ char *line;
5955 char *w, *state;
295edddf 5956 size_t l;
74df0fca 5957 int r;
295edddf 5958
74df0fca
LP
5959 r = proc_cmdline(&line);
5960 if (r < 0)
5961 return r;
5962 if (r == 0) /* Container ... */
5963 return 1;
295edddf 5964
74df0fca 5965 FOREACH_WORD_QUOTED(w, l, line, state)
85ca9433 5966 if (l == 23 && strneq(w, "systemd.restore_state=0", 23))
74df0fca
LP
5967 return 0;
5968
5969 return 1;
5970}
5971
5972int proc_cmdline(char **ret) {
5973 int r;
5974
5975 if (detect_container(NULL) > 0) {
02bb6cda
LP
5976 char *buf, *p;
5977 size_t sz = 0;
5978
5979 r = read_full_file("/proc/1/cmdline", &buf, &sz);
5980 if (r < 0)
5981 return r;
5982
5983 for (p = buf; p + 1 < buf + sz; p++)
5984 if (*p == 0)
5985 *p = ' ';
5986
5987 *p = 0;
5988 *ret = buf;
5989 return 1;
295edddf
TG
5990 }
5991
74df0fca
LP
5992 r = read_one_line_file("/proc/cmdline", ret);
5993 if (r < 0)
5994 return r;
295edddf 5995
74df0fca 5996 return 1;
295edddf 5997}
bc9fd78c
LP
5998
5999int container_get_leader(const char *machine, pid_t *pid) {
6000 _cleanup_free_ char *s = NULL, *class = NULL;
6001 const char *p;
6002 pid_t leader;
6003 int r;
6004
6005 assert(machine);
6006 assert(pid);
6007
6008 p = strappenda("/run/systemd/machines/", machine);
6009 r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
6010 if (r == -ENOENT)
6011 return -EHOSTDOWN;
6012 if (r < 0)
6013 return r;
6014 if (!s)
6015 return -EIO;
6016
6017 if (!streq_ptr(class, "container"))
6018 return -EIO;
6019
6020 r = parse_pid(s, &leader);
6021 if (r < 0)
6022 return r;
6023 if (leader <= 1)
6024 return -EIO;
6025
6026 *pid = leader;
6027 return 0;
6028}
6029
a4475f57
LP
6030int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *root_fd) {
6031 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1;
6032 const char *pidns, *mntns, *root;
bc9fd78c
LP
6033 int rfd;
6034
6035 assert(pid >= 0);
a4475f57
LP
6036 assert(pidns_fd);
6037 assert(mntns_fd);
bc9fd78c
LP
6038 assert(root_fd);
6039
a4475f57
LP
6040 mntns = procfs_file_alloca(pid, "ns/mnt");
6041 mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
6042 if (mntnsfd < 0)
6043 return -errno;
6044
6045 pidns = procfs_file_alloca(pid, "ns/pid");
6046 pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
6047 if (pidnsfd < 0)
bc9fd78c
LP
6048 return -errno;
6049
6050 root = procfs_file_alloca(pid, "root");
6051 rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
6052 if (rfd < 0)
6053 return -errno;
6054
a4475f57
LP
6055 *pidns_fd = pidnsfd;
6056 *mntns_fd = mntnsfd;
bc9fd78c 6057 *root_fd = rfd;
a4475f57
LP
6058 pidnsfd = -1;
6059 mntnsfd = -1;
bc9fd78c
LP
6060
6061 return 0;
6062}
6063
a4475f57
LP
6064int namespace_enter(int pidns_fd, int mntns_fd, int root_fd) {
6065 assert(pidns_fd >= 0);
6066 assert(mntns_fd >= 0);
bc9fd78c
LP
6067 assert(root_fd >= 0);
6068
a4475f57
LP
6069 if (setns(pidns_fd, CLONE_NEWPID) < 0)
6070 return -errno;
6071
6072 if (setns(mntns_fd, CLONE_NEWNS) < 0)
bc9fd78c
LP
6073 return -errno;
6074
6075 if (fchdir(root_fd) < 0)
6076 return -errno;
6077
6078 if (chroot(".") < 0)
6079 return -errno;
6080
5e2b3214
LP
6081 if (setresgid(0, 0, 0) < 0)
6082 return -errno;
6083
6084 if (setresuid(0, 0, 0) < 0)
6085 return -errno;
6086
bc9fd78c
LP
6087 return 0;
6088}
bf108e55
LP
6089
6090bool pid_valid(pid_t pid) {
6091 if (pid <= 0)
6092 return false;
6093
6094 if (kill(pid, 0) >= 0)
6095 return true;
6096
6097 return errno != ESRCH;
6098}
eff05270
LP
6099
6100int getpeercred(int fd, struct ucred *ucred) {
6101 socklen_t n = sizeof(struct ucred);
6102 struct ucred u;
6103 int r;
6104
6105 assert(fd >= 0);
6106 assert(ucred);
6107
6108 r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n);
6109 if (r < 0)
6110 return -errno;
6111
6112 if (n != sizeof(struct ucred))
6113 return -EIO;
6114
6115 /* Check if the data is actually useful and not suppressed due
6116 * to namespacing issues */
6117 if (u.pid <= 0)
6118 return -ENODATA;
6119
6120 *ucred = u;
6121 return 0;
6122}
6123
6124int getpeersec(int fd, char **ret) {
6125 socklen_t n = 64;
6126 char *s;
6127 int r;
6128
6129 assert(fd >= 0);
6130 assert(ret);
6131
6132 s = new0(char, n);
6133 if (!s)
6134 return -ENOMEM;
6135
6136 r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
6137 if (r < 0) {
6138 free(s);
6139
6140 if (errno != ERANGE)
6141 return -errno;
6142
6143 s = new0(char, n);
6144 if (!s)
6145 return -ENOMEM;
6146
6147 r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
6148 if (r < 0) {
6149 free(s);
6150 return -errno;
6151 }
6152 }
6153
ae98841e
LP
6154 if (isempty(s)) {
6155 free(s);
6156 return -ENOTSUP;
6157 }
6158
eff05270
LP
6159 *ret = s;
6160 return 0;
6161}