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