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