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