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