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