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