]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/util.c
util: modernize loop_read() and loop_write() a bit
[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
9bf3b535
LP
2258void random_bytes(void *p, size_t n) {
2259 static bool srand_called = false;
a05f97b3 2260 _cleanup_close_ int fd;
9bf3b535
LP
2261 ssize_t k;
2262 uint8_t *q;
d3782d60 2263
ac0930c8
LP
2264 fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
2265 if (fd < 0)
d3782d60
LP
2266 goto fallback;
2267
9bf3b535
LP
2268 k = loop_read(fd, p, n, true);
2269 if (k < 0 || (size_t) k != n)
d3782d60
LP
2270 goto fallback;
2271
9bf3b535 2272 return;
d3782d60
LP
2273
2274fallback:
d3782d60 2275
9bf3b535 2276 if (!srand_called) {
a3b6fafe 2277
9bf3b535
LP
2278#ifdef HAVE_SYS_AUXV_H
2279 /* The kernel provides us with a bit of entropy in
2280 * auxv, so let's try to make use of that to seed the
2281 * pseudo-random generator. It's better than
2282 * nothing... */
a3b6fafe 2283
9bf3b535
LP
2284 void *auxv;
2285
2286 auxv = (void*) getauxval(AT_RANDOM);
2287 if (auxv)
2288 srand(*(unsigned*) auxv);
2289 else
2290#endif
2291 srand(time(NULL) + gettid());
a3b6fafe 2292
9bf3b535
LP
2293 srand_called = true;
2294 }
a3b6fafe 2295
9bf3b535
LP
2296 /* If some idiot made /dev/urandom unavailable to us, he'll
2297 * get a PRNG instead. */
2298 for (q = p; q < (uint8_t*) p + n; q ++)
2299 *q = rand();
a3b6fafe
LP
2300}
2301
5b6319dc
LP
2302void rename_process(const char name[8]) {
2303 assert(name);
2304
5d6b1584
LP
2305 /* This is a like a poor man's setproctitle(). It changes the
2306 * comm field, argv[0], and also the glibc's internally used
2307 * name of the process. For the first one a limit of 16 chars
2308 * applies, to the second one usually one of 10 (i.e. length
2309 * of "/sbin/init"), to the third one one of 7 (i.e. length of
2310 * "systemd"). If you pass a longer string it will be
2311 * truncated */
5b6319dc 2312
5d6b1584 2313 prctl(PR_SET_NAME, name);
5b6319dc
LP
2314
2315 if (program_invocation_name)
2316 strncpy(program_invocation_name, name, strlen(program_invocation_name));
9a0e6896
LP
2317
2318 if (saved_argc > 0) {
2319 int i;
2320
2321 if (saved_argv[0])
2322 strncpy(saved_argv[0], name, strlen(saved_argv[0]));
2323
2324 for (i = 1; i < saved_argc; i++) {
2325 if (!saved_argv[i])
2326 break;
2327
2328 memset(saved_argv[i], 0, strlen(saved_argv[i]));
2329 }
2330 }
5b6319dc
LP
2331}
2332
7d793605
LP
2333void sigset_add_many(sigset_t *ss, ...) {
2334 va_list ap;
2335 int sig;
2336
2337 assert(ss);
2338
2339 va_start(ap, ss);
2340 while ((sig = va_arg(ap, int)) > 0)
2341 assert_se(sigaddset(ss, sig) == 0);
2342 va_end(ap);
2343}
2344
ef2f1067
LP
2345char* gethostname_malloc(void) {
2346 struct utsname u;
2347
2348 assert_se(uname(&u) >= 0);
2349
344de609 2350 if (!isempty(u.nodename) && !streq(u.nodename, "(none)"))
ef2f1067
LP
2351 return strdup(u.nodename);
2352
2353 return strdup(u.sysname);
2354}
2355
344de609
LP
2356bool hostname_is_set(void) {
2357 struct utsname u;
2358
2359 assert_se(uname(&u) >= 0);
2360
2361 return !isempty(u.nodename) && !streq(u.nodename, "(none)");
2362}
2363
7c5f152a 2364static char *lookup_uid(uid_t uid) {
ef2f1067 2365 long bufsize;
a05f97b3
LP
2366 char *name;
2367 _cleanup_free_ char *buf = NULL;
ef2f1067 2368 struct passwd pwbuf, *pw = NULL;
ef2f1067
LP
2369
2370 /* Shortcut things to avoid NSS lookups */
2371 if (uid == 0)
2372 return strdup("root");
2373
7c5f152a
LP
2374 bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
2375 if (bufsize <= 0)
ef2f1067
LP
2376 bufsize = 4096;
2377
7c5f152a
LP
2378 buf = malloc(bufsize);
2379 if (!buf)
ef2f1067
LP
2380 return NULL;
2381
a05f97b3
LP
2382 if (getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0 && pw)
2383 return strdup(pw->pw_name);
ef2f1067
LP
2384
2385 if (asprintf(&name, "%lu", (unsigned long) uid) < 0)
2386 return NULL;
2387
2388 return name;
2389}
2390
7c5f152a
LP
2391char* getlogname_malloc(void) {
2392 uid_t uid;
2393 struct stat st;
2394
2395 if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0)
2396 uid = st.st_uid;
2397 else
2398 uid = getuid();
2399
2400 return lookup_uid(uid);
2401}
2402
2403char *getusername_malloc(void) {
2404 const char *e;
2405
2406 e = getenv("USER");
2407 if (e)
2408 return strdup(e);
2409
2410 return lookup_uid(getuid());
2411}
2412
fc116c6a
LP
2413int getttyname_malloc(int fd, char **r) {
2414 char path[PATH_MAX], *c;
618e02c7 2415 int k;
8c6db833
LP
2416
2417 assert(r);
ef2f1067 2418
a05f97b3 2419 k = ttyname_r(fd, path, sizeof(path));
27373e44 2420 if (k > 0)
618e02c7 2421 return -k;
ef2f1067
LP
2422
2423 char_array_0(path);
2424
a05f97b3
LP
2425 c = strdup(startswith(path, "/dev/") ? path + 5 : path);
2426 if (!c)
8c6db833
LP
2427 return -ENOMEM;
2428
2429 *r = c;
2430 return 0;
2431}
2432
fc116c6a
LP
2433int getttyname_harder(int fd, char **r) {
2434 int k;
2435 char *s;
2436
a05f97b3
LP
2437 k = getttyname_malloc(fd, &s);
2438 if (k < 0)
fc116c6a
LP
2439 return k;
2440
2441 if (streq(s, "tty")) {
2442 free(s);
4d6d6518 2443 return get_ctty(0, NULL, r);
fc116c6a
LP
2444 }
2445
2446 *r = s;
2447 return 0;
2448}
2449
4d6d6518 2450int get_ctty_devnr(pid_t pid, dev_t *d) {
b4696bce
SP
2451 int r;
2452 _cleanup_free_ char *line = NULL;
2453 const char *p;
fc116c6a 2454 unsigned long ttynr;
fc116c6a 2455
49aa47c7 2456 assert(pid >= 0);
49aa47c7 2457
b4696bce
SP
2458 p = procfs_file_alloca(pid, "stat");
2459 r = read_one_line_file(p, &line);
2460 if (r < 0)
2461 return r;
fc116c6a 2462
4d6d6518
LP
2463 p = strrchr(line, ')');
2464 if (!p)
fc116c6a
LP
2465 return -EIO;
2466
2467 p++;
2468
2469 if (sscanf(p, " "
2470 "%*c " /* state */
2471 "%*d " /* ppid */
2472 "%*d " /* pgrp */
2473 "%*d " /* session */
2474 "%lu ", /* ttynr */
2475 &ttynr) != 1)
2476 return -EIO;
2477
11dc5d2b
LP
2478 if (major(ttynr) == 0 && minor(ttynr) == 0)
2479 return -ENOENT;
2480
0bee65f0
LP
2481 if (d)
2482 *d = (dev_t) ttynr;
2483
fc116c6a
LP
2484 return 0;
2485}
2486
4d6d6518 2487int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
fc116c6a 2488 int k;
fa70beaa 2489 char fn[sizeof("/dev/char/")-1 + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *s, *b, *p;
fc116c6a
LP
2490 dev_t devnr;
2491
2492 assert(r);
2493
4d6d6518
LP
2494 k = get_ctty_devnr(pid, &devnr);
2495 if (k < 0)
fc116c6a
LP
2496 return k;
2497
2498 snprintf(fn, sizeof(fn), "/dev/char/%u:%u", major(devnr), minor(devnr));
fc116c6a 2499
23406ce5
LP
2500 k = readlink_malloc(fn, &s);
2501 if (k < 0) {
fc116c6a
LP
2502
2503 if (k != -ENOENT)
2504 return k;
2505
46824d0e
LP
2506 /* This is an ugly hack */
2507 if (major(devnr) == 136) {
2508 if (asprintf(&b, "pts/%lu", (unsigned long) minor(devnr)) < 0)
2509 return -ENOMEM;
2510
2511 *r = b;
2512 if (_devnr)
2513 *_devnr = devnr;
2514
2515 return 0;
2516 }
2517
fc116c6a
LP
2518 /* Probably something like the ptys which have no
2519 * symlink in /dev/char. Let's return something
2520 * vaguely useful. */
2521
23406ce5
LP
2522 b = strdup(fn + 5);
2523 if (!b)
fc116c6a
LP
2524 return -ENOMEM;
2525
2526 *r = b;
46824d0e
LP
2527 if (_devnr)
2528 *_devnr = devnr;
2529
fc116c6a
LP
2530 return 0;
2531 }
2532
2533 if (startswith(s, "/dev/"))
2534 p = s + 5;
2535 else if (startswith(s, "../"))
2536 p = s + 3;
2537 else
2538 p = s;
2539
2540 b = strdup(p);
2541 free(s);
2542
2543 if (!b)
2544 return -ENOMEM;
2545
2546 *r = b;
46824d0e
LP
2547 if (_devnr)
2548 *_devnr = devnr;
2549
fc116c6a
LP
2550 return 0;
2551}
2552
f56d5db9 2553int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
8c6db833
LP
2554 DIR *d;
2555 int ret = 0;
2556
2557 assert(fd >= 0);
2558
2559 /* This returns the first error we run into, but nevertheless
7925c22a 2560 * tries to go on. This closes the passed fd. */
8c6db833 2561
d4d046e3
LP
2562 d = fdopendir(fd);
2563 if (!d) {
8c6db833 2564 close_nointr_nofail(fd);
4c633005
LP
2565
2566 return errno == ENOENT ? 0 : -errno;
8c6db833
LP
2567 }
2568
2569 for (;;) {
7d5e9c0f 2570 struct dirent *de;
7925c22a
LP
2571 bool is_dir, keep_around;
2572 struct stat st;
8c6db833
LP
2573 int r;
2574
3fd11280
FW
2575 errno = 0;
2576 de = readdir(d);
2577 if (!de && errno != 0) {
2578 if (ret == 0)
2579 ret = -errno;
8c6db833
LP
2580 break;
2581 }
2582
2583 if (!de)
2584 break;
2585
2586 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
2587 continue;
2588
7925c22a
LP
2589 if (de->d_type == DT_UNKNOWN ||
2590 honour_sticky ||
2591 (de->d_type == DT_DIR && root_dev)) {
8c6db833 2592 if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
4c633005 2593 if (ret == 0 && errno != ENOENT)
8c6db833
LP
2594 ret = -errno;
2595 continue;
2596 }
2597
2598 is_dir = S_ISDIR(st.st_mode);
7925c22a
LP
2599 keep_around =
2600 honour_sticky &&
2601 (st.st_uid == 0 || st.st_uid == getuid()) &&
2602 (st.st_mode & S_ISVTX);
ad293f5a 2603 } else {
8c6db833 2604 is_dir = de->d_type == DT_DIR;
7925c22a 2605 keep_around = false;
ad293f5a 2606 }
8c6db833
LP
2607
2608 if (is_dir) {
2609 int subdir_fd;
8c6db833 2610
597f43c7 2611 /* if root_dev is set, remove subdirectories only, if device is same as dir */
7925c22a
LP
2612 if (root_dev && st.st_dev != root_dev->st_dev)
2613 continue;
8c6db833 2614
7925c22a
LP
2615 subdir_fd = openat(fd, de->d_name,
2616 O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
2617 if (subdir_fd < 0) {
2618 if (ret == 0 && errno != ENOENT)
2619 ret = -errno;
2620 continue;
2621 }
2622
b3d28469 2623 r = rm_rf_children_dangerous(subdir_fd, only_dirs, honour_sticky, root_dev);
7925c22a
LP
2624 if (r < 0 && ret == 0)
2625 ret = r;
2626
2627 if (!keep_around)
2628 if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
ad293f5a
LP
2629 if (ret == 0 && errno != ENOENT)
2630 ret = -errno;
2631 }
2632
2633 } else if (!only_dirs && !keep_around) {
8c6db833
LP
2634
2635 if (unlinkat(fd, de->d_name, 0) < 0) {
4c633005 2636 if (ret == 0 && errno != ENOENT)
8c6db833
LP
2637 ret = -errno;
2638 }
2639 }
2640 }
2641
2642 closedir(d);
2643
2644 return ret;
2645}
2646
44a6b1b6 2647_pure_ static int is_temporary_fs(struct statfs *s) {
943aad8c 2648 assert(s);
73020ab2
SL
2649
2650 return F_TYPE_EQUAL(s->f_type, TMPFS_MAGIC) ||
2651 F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC);
943aad8c
ZJS
2652}
2653
f56d5db9
LP
2654int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
2655 struct statfs s;
2656
2657 assert(fd >= 0);
2658
2659 if (fstatfs(fd, &s) < 0) {
2660 close_nointr_nofail(fd);
2661 return -errno;
2662 }
2663
2664 /* We refuse to clean disk file systems with this call. This
2665 * is extra paranoia just to be sure we never ever remove
2666 * non-state data */
943aad8c 2667 if (!is_temporary_fs(&s)) {
f56d5db9
LP
2668 log_error("Attempted to remove disk file system, and we can't allow that.");
2669 close_nointr_nofail(fd);
2670 return -EPERM;
2671 }
2672
2673 return rm_rf_children_dangerous(fd, only_dirs, honour_sticky, root_dev);
2674}
2675
2676static int rm_rf_internal(const char *path, bool only_dirs, bool delete_root, bool honour_sticky, bool dangerous) {
2677 int fd, r;
2678 struct statfs s;
8c6db833
LP
2679
2680 assert(path);
2681
f56d5db9
LP
2682 /* We refuse to clean the root file system with this
2683 * call. This is extra paranoia to never cause a really
2684 * seriously broken system. */
2685 if (path_equal(path, "/")) {
2686 log_error("Attempted to remove entire root file system, and we can't allow that.");
2687 return -EPERM;
2688 }
461b1822 2689
d4d046e3
LP
2690 fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
2691 if (fd < 0) {
8c6db833
LP
2692
2693 if (errno != ENOTDIR)
2694 return -errno;
2695
f56d5db9
LP
2696 if (!dangerous) {
2697 if (statfs(path, &s) < 0)
2698 return -errno;
2699
943aad8c 2700 if (!is_temporary_fs(&s)) {
f56d5db9
LP
2701 log_error("Attempted to remove disk file system, and we can't allow that.");
2702 return -EPERM;
2703 }
2704 }
2705
8c6db833 2706 if (delete_root && !only_dirs)
d4d046e3 2707 if (unlink(path) < 0 && errno != ENOENT)
8c6db833
LP
2708 return -errno;
2709
2710 return 0;
2711 }
2712
f56d5db9
LP
2713 if (!dangerous) {
2714 if (fstatfs(fd, &s) < 0) {
2715 close_nointr_nofail(fd);
2716 return -errno;
2717 }
ad293f5a 2718
943aad8c 2719 if (!is_temporary_fs(&s)) {
f56d5db9
LP
2720 log_error("Attempted to remove disk file system, and we can't allow that.");
2721 close_nointr_nofail(fd);
2722 return -EPERM;
2723 }
2724 }
2725
2726 r = rm_rf_children_dangerous(fd, only_dirs, honour_sticky, NULL);
ad293f5a
LP
2727 if (delete_root) {
2728
8d53b453 2729 if (honour_sticky && file_is_priv_sticky(path) > 0)
ad293f5a 2730 return r;
8c6db833 2731
e27796a0 2732 if (rmdir(path) < 0 && errno != ENOENT) {
8c6db833
LP
2733 if (r == 0)
2734 r = -errno;
2735 }
ad293f5a 2736 }
8c6db833
LP
2737
2738 return r;
2739}
2740
f56d5db9
LP
2741int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) {
2742 return rm_rf_internal(path, only_dirs, delete_root, honour_sticky, false);
2743}
2744
2745int rm_rf_dangerous(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) {
2746 return rm_rf_internal(path, only_dirs, delete_root, honour_sticky, true);
2747}
2748
8c6db833
LP
2749int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
2750 assert(path);
2751
2752 /* Under the assumption that we are running privileged we
2753 * first change the access mode and only then hand out
2754 * ownership to avoid a window where access is too open. */
2755
8d53b453
LP
2756 if (mode != (mode_t) -1)
2757 if (chmod(path, mode) < 0)
2758 return -errno;
8c6db833 2759
8d53b453
LP
2760 if (uid != (uid_t) -1 || gid != (gid_t) -1)
2761 if (chown(path, uid, gid) < 0)
2762 return -errno;
8c6db833
LP
2763
2764 return 0;
ef2f1067
LP
2765}
2766
f4b47811
LP
2767int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) {
2768 assert(fd >= 0);
2769
2770 /* Under the assumption that we are running privileged we
2771 * first change the access mode and only then hand out
2772 * ownership to avoid a window where access is too open. */
2773
9588bc32
LP
2774 if (mode != (mode_t) -1)
2775 if (fchmod(fd, mode) < 0)
2776 return -errno;
f4b47811 2777
9588bc32
LP
2778 if (uid != (uid_t) -1 || gid != (gid_t) -1)
2779 if (fchown(fd, uid, gid) < 0)
2780 return -errno;
f4b47811
LP
2781
2782 return 0;
2783}
2784
82c121a4
LP
2785cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
2786 cpu_set_t *r;
2787 unsigned n = 1024;
2788
2789 /* Allocates the cpuset in the right size */
2790
2791 for (;;) {
2792 if (!(r = CPU_ALLOC(n)))
2793 return NULL;
2794
2795 if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), r) >= 0) {
2796 CPU_ZERO_S(CPU_ALLOC_SIZE(n), r);
2797
2798 if (ncpus)
2799 *ncpus = n;
2800
2801 return r;
2802 }
2803
2804 CPU_FREE(r);
2805
2806 if (errno != EINVAL)
2807 return NULL;
2808
2809 n *= 2;
2810 }
2811}
2812
984a2be4 2813int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) {
9ab7a8d2 2814 static const char status_indent[] = " "; /* "[" STATUS "] " */
669bec5d
LP
2815 _cleanup_free_ char *s = NULL;
2816 _cleanup_close_ int fd = -1;
b92bea5d 2817 struct iovec iovec[6] = {};
81beb750 2818 int n = 0;
984a2be4 2819 static bool prev_ephemeral;
9e58ff9c
LP
2820
2821 assert(format);
2822
9ab7a8d2 2823 /* This is independent of logging, as status messages are
9e58ff9c
LP
2824 * optional and go exclusively to the console. */
2825
2826 if (vasprintf(&s, format, ap) < 0)
669bec5d 2827 return log_oom();
9e58ff9c 2828
67e5cc4f 2829 fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
81beb750 2830 if (fd < 0)
669bec5d 2831 return fd;
9e58ff9c 2832
67e5cc4f 2833 if (ellipse) {
9ab7a8d2
MS
2834 char *e;
2835 size_t emax, sl;
2836 int c;
2837
67e5cc4f
LP
2838 c = fd_columns(fd);
2839 if (c <= 0)
2840 c = 80;
81beb750 2841
669bec5d 2842 sl = status ? sizeof(status_indent)-1 : 0;
9ab7a8d2
MS
2843
2844 emax = c - sl - 1;
2845 if (emax < 3)
2846 emax = 3;
81beb750 2847
67e5cc4f
LP
2848 e = ellipsize(s, emax, 75);
2849 if (e) {
2850 free(s);
2851 s = e;
2852 }
81beb750
LP
2853 }
2854
984a2be4
MS
2855 if (prev_ephemeral)
2856 IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE);
2857 prev_ephemeral = ephemeral;
2858
9ab7a8d2
MS
2859 if (status) {
2860 if (!isempty(status)) {
2861 IOVEC_SET_STRING(iovec[n++], "[");
2862 IOVEC_SET_STRING(iovec[n++], status);
2863 IOVEC_SET_STRING(iovec[n++], "] ");
2864 } else
2865 IOVEC_SET_STRING(iovec[n++], status_indent);
81beb750
LP
2866 }
2867
9ab7a8d2 2868 IOVEC_SET_STRING(iovec[n++], s);
984a2be4
MS
2869 if (!ephemeral)
2870 IOVEC_SET_STRING(iovec[n++], "\n");
81beb750 2871
669bec5d
LP
2872 if (writev(fd, iovec, n) < 0)
2873 return -errno;
9e58ff9c 2874
669bec5d 2875 return 0;
9e58ff9c
LP
2876}
2877
984a2be4 2878int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) {
c846ff47 2879 va_list ap;
669bec5d 2880 int r;
c846ff47
LP
2881
2882 assert(format);
2883
2884 va_start(ap, format);
984a2be4 2885 r = status_vprintf(status, ellipse, ephemeral, format, ap);
c846ff47 2886 va_end(ap);
669bec5d
LP
2887
2888 return r;
c846ff47
LP
2889}
2890
669bec5d 2891int status_welcome(void) {
669bec5d 2892 _cleanup_free_ char *pretty_name = NULL, *ansi_color = NULL;
9588bc32 2893 int r;
669bec5d
LP
2894
2895 r = parse_env_file("/etc/os-release", NEWLINE,
2896 "PRETTY_NAME", &pretty_name,
2897 "ANSI_COLOR", &ansi_color,
2898 NULL);
9588bc32 2899
669bec5d
LP
2900 if (r < 0 && r != -ENOENT)
2901 log_warning("Failed to read /etc/os-release: %s", strerror(-r));
2902
f620dff8 2903 return status_printf(NULL, false, false,
669bec5d
LP
2904 "\nWelcome to \x1B[%sm%s\x1B[0m!\n",
2905 isempty(ansi_color) ? "1" : ansi_color,
2906 isempty(pretty_name) ? "Linux" : pretty_name);
c846ff47
LP
2907}
2908
fab56fc5
LP
2909char *replace_env(const char *format, char **env) {
2910 enum {
2911 WORD,
c24eb49e 2912 CURLY,
fab56fc5
LP
2913 VARIABLE
2914 } state = WORD;
2915
2916 const char *e, *word = format;
2917 char *r = NULL, *k;
2918
2919 assert(format);
2920
2921 for (e = format; *e; e ++) {
2922
2923 switch (state) {
2924
2925 case WORD:
2926 if (*e == '$')
c24eb49e 2927 state = CURLY;
fab56fc5
LP
2928 break;
2929
c24eb49e
LP
2930 case CURLY:
2931 if (*e == '{') {
fab56fc5
LP
2932 if (!(k = strnappend(r, word, e-word-1)))
2933 goto fail;
2934
2935 free(r);
2936 r = k;
2937
2938 word = e-1;
2939 state = VARIABLE;
2940
2941 } else if (*e == '$') {
2942 if (!(k = strnappend(r, word, e-word)))
2943 goto fail;
2944
2945 free(r);
2946 r = k;
2947
2948 word = e+1;
2949 state = WORD;
2950 } else
2951 state = WORD;
2952 break;
2953
2954 case VARIABLE:
c24eb49e 2955 if (*e == '}') {
b95cf362 2956 const char *t;
fab56fc5 2957
4d1a6904 2958 t = strempty(strv_env_get_n(env, word+2, e-word-2));
fab56fc5 2959
4d1a6904
LP
2960 k = strappend(r, t);
2961 if (!k)
b95cf362 2962 goto fail;
fab56fc5 2963
b95cf362
LP
2964 free(r);
2965 r = k;
fab56fc5 2966
b95cf362 2967 word = e+1;
fab56fc5
LP
2968 state = WORD;
2969 }
2970 break;
2971 }
2972 }
2973
2974 if (!(k = strnappend(r, word, e-word)))
2975 goto fail;
2976
2977 free(r);
2978 return k;
2979
2980fail:
2981 free(r);
2982 return NULL;
2983}
2984
2985char **replace_env_argv(char **argv, char **env) {
2986 char **r, **i;
c24eb49e
LP
2987 unsigned k = 0, l = 0;
2988
2989 l = strv_length(argv);
fab56fc5 2990
c24eb49e 2991 if (!(r = new(char*, l+1)))
fab56fc5
LP
2992 return NULL;
2993
2994 STRV_FOREACH(i, argv) {
c24eb49e
LP
2995
2996 /* If $FOO appears as single word, replace it by the split up variable */
b95cf362
LP
2997 if ((*i)[0] == '$' && (*i)[1] != '{') {
2998 char *e;
2999 char **w, **m;
3000 unsigned q;
c24eb49e 3001
4d1a6904
LP
3002 e = strv_env_get(env, *i+1);
3003 if (e) {
c24eb49e
LP
3004
3005 if (!(m = strv_split_quoted(e))) {
3006 r[k] = NULL;
3007 strv_free(r);
3008 return NULL;
3009 }
b95cf362
LP
3010 } else
3011 m = NULL;
c24eb49e 3012
b95cf362
LP
3013 q = strv_length(m);
3014 l = l + q - 1;
c24eb49e 3015
b95cf362
LP
3016 if (!(w = realloc(r, sizeof(char*) * (l+1)))) {
3017 r[k] = NULL;
3018 strv_free(r);
3019 strv_free(m);
3020 return NULL;
3021 }
c24eb49e 3022
b95cf362
LP
3023 r = w;
3024 if (m) {
c24eb49e
LP
3025 memcpy(r + k, m, q * sizeof(char*));
3026 free(m);
c24eb49e 3027 }
b95cf362
LP
3028
3029 k += q;
3030 continue;
c24eb49e
LP
3031 }
3032
3033 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
fab56fc5
LP
3034 if (!(r[k++] = replace_env(*i, env))) {
3035 strv_free(r);
3036 return NULL;
3037 }
3038 }
3039
3040 r[k] = NULL;
3041 return r;
3042}
3043
81beb750 3044int fd_columns(int fd) {
b92bea5d 3045 struct winsize ws = {};
81beb750
LP
3046
3047 if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
3048 return -errno;
3049
3050 if (ws.ws_col <= 0)
3051 return -EIO;
3052
3053 return ws.ws_col;
3054}
3055
28917d7d 3056unsigned columns(void) {
fa776d8e 3057 const char *e;
7009eec2 3058 int c;
fa776d8e 3059
28917d7d
LP
3060 if (_likely_(cached_columns > 0))
3061 return cached_columns;
11f96fac 3062
28917d7d
LP
3063 c = 0;
3064 e = getenv("COLUMNS");
3065 if (e)
7009eec2 3066 safe_atoi(e, &c);
fa776d8e 3067
28917d7d
LP
3068 if (c <= 0)
3069 c = fd_columns(STDOUT_FILENO);
fa776d8e 3070
28917d7d
LP
3071 if (c <= 0)
3072 c = 80;
11f96fac 3073
28917d7d
LP
3074 cached_columns = c;
3075 return c;
11f96fac
ZJS
3076}
3077
8f2d43a0 3078int fd_lines(int fd) {
b92bea5d 3079 struct winsize ws = {};
8f2d43a0
LP
3080
3081 if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
3082 return -errno;
3083
3084 if (ws.ws_row <= 0)
3085 return -EIO;
3086
3087 return ws.ws_row;
3088}
3089
3090unsigned lines(void) {
8f2d43a0 3091 const char *e;
ed757c0c 3092 unsigned l;
8f2d43a0 3093
ed757c0c
LP
3094 if (_likely_(cached_lines > 0))
3095 return cached_lines;
8f2d43a0 3096
ed757c0c 3097 l = 0;
8f2d43a0
LP
3098 e = getenv("LINES");
3099 if (e)
ed757c0c 3100 safe_atou(e, &l);
8f2d43a0 3101
ed757c0c
LP
3102 if (l <= 0)
3103 l = fd_lines(STDOUT_FILENO);
8f2d43a0 3104
ed757c0c
LP
3105 if (l <= 0)
3106 l = 24;
8f2d43a0 3107
ed757c0c
LP
3108 cached_lines = l;
3109 return cached_lines;
3110}
3111
3112/* intended to be used as a SIGWINCH sighandler */
3113void columns_lines_cache_reset(int signum) {
3114 cached_columns = 0;
3115 cached_lines = 0;
3116}
3117
3118bool on_tty(void) {
3119 static int cached_on_tty = -1;
3120
3121 if (_unlikely_(cached_on_tty < 0))
3122 cached_on_tty = isatty(STDOUT_FILENO) > 0;
3123
3124 return cached_on_tty;
8f2d43a0
LP
3125}
3126
b4f10a5e 3127int running_in_chroot(void) {
b92bea5d 3128 struct stat a = {}, b = {};
b4f10a5e
LP
3129
3130 /* Only works as root */
b4f10a5e
LP
3131 if (stat("/proc/1/root", &a) < 0)
3132 return -errno;
3133
3134 if (stat("/", &b) < 0)
3135 return -errno;
3136
3137 return
3138 a.st_dev != b.st_dev ||
3139 a.st_ino != b.st_ino;
3140}
3141
f405e86d 3142static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
72f59706 3143 size_t x;
8fe914ec
LP
3144 char *r;
3145
3146 assert(s);
3147 assert(percent <= 100);
72f59706 3148 assert(new_length >= 3);
8fe914ec 3149
72f59706
LP
3150 if (old_length <= 3 || old_length <= new_length)
3151 return strndup(s, old_length);
8fe914ec 3152
72f59706
LP
3153 r = new0(char, new_length+1);
3154 if (!r)
a6f0104a 3155 return NULL;
8fe914ec 3156
72f59706 3157 x = (new_length * percent) / 100;
8fe914ec 3158
72f59706
LP
3159 if (x > new_length - 3)
3160 x = new_length - 3;
8fe914ec
LP
3161
3162 memcpy(r, s, x);
3163 r[x] = '.';
3164 r[x+1] = '.';
3165 r[x+2] = '.';
3166 memcpy(r + x + 3,
72f59706
LP
3167 s + old_length - (new_length - x - 3),
3168 new_length - x - 3);
8fe914ec
LP
3169
3170 return r;
3171}
3172
f405e86d
SL
3173char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
3174 size_t x;
3175 char *e;
3176 const char *i, *j;
3177 unsigned k, len, len2;
3178
3179 assert(s);
3180 assert(percent <= 100);
3181 assert(new_length >= 3);
3182
3183 /* if no multibyte characters use ascii_ellipsize_mem for speed */
3184 if (ascii_is_valid(s))
3185 return ascii_ellipsize_mem(s, old_length, new_length, percent);
3186
3187 if (old_length <= 3 || old_length <= new_length)
3188 return strndup(s, old_length);
3189
3190 x = (new_length * percent) / 100;
3191
3192 if (x > new_length - 3)
3193 x = new_length - 3;
3194
3195 k = 0;
3196 for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) {
3197 int c;
3198
3199 c = utf8_encoded_to_unichar(i);
3200 if (c < 0)
3201 return NULL;
3202 k += unichar_iswide(c) ? 2 : 1;
3203 }
3204
3205 if (k > x) /* last character was wide and went over quota */
3206 x ++;
3207
3208 for (j = s + old_length; k < new_length && j > i; ) {
3209 int c;
3210
3211 j = utf8_prev_char(j);
3212 c = utf8_encoded_to_unichar(j);
3213 if (c < 0)
3214 return NULL;
3215 k += unichar_iswide(c) ? 2 : 1;
3216 }
3217 assert(i <= j);
3218
3219 /* we don't actually need to ellipsize */
3220 if (i == j)
3221 return memdup(s, old_length + 1);
3222
3223 /* make space for ellipsis */
3224 j = utf8_next_char(j);
3225
3226 len = i - s;
3227 len2 = s + old_length - j;
3228 e = new(char, len + 3 + len2 + 1);
3229 if (!e)
3230 return NULL;
3231
3232 /*
3233 printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n",
3234 old_length, new_length, x, len, len2, k);
3235 */
3236
3237 memcpy(e, s, len);
3238 e[len] = 0xe2; /* tri-dot ellipsis: … */
3239 e[len + 1] = 0x80;
3240 e[len + 2] = 0xa6;
3241
3242 memcpy(e + len + 3, j, len2 + 1);
3243
3244 return e;
3245}
3246
72f59706
LP
3247char *ellipsize(const char *s, size_t length, unsigned percent) {
3248 return ellipsize_mem(s, strlen(s), length, percent);
3249}
3250
f6144808
LP
3251int touch(const char *path) {
3252 int fd;
3253
3254 assert(path);
3255
73836c5c
LP
3256 /* This just opens the file for writing, ensuring it
3257 * exists. It doesn't call utimensat() the way /usr/bin/touch
3258 * does it. */
3259
3260 fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0644);
3261 if (fd < 0)
f6144808
LP
3262 return -errno;
3263
3264 close_nointr_nofail(fd);
3265 return 0;
3266}
afea26ad 3267
97c4a07d 3268char *unquote(const char *s, const char* quotes) {
11ce3427
LP
3269 size_t l;
3270 assert(s);
3271
73836c5c
LP
3272 /* This is rather stupid, simply removes the heading and
3273 * trailing quotes if there is one. Doesn't care about
57f30678
LP
3274 * escaping or anything. We should make this smarter one
3275 * day...*/
73836c5c 3276
31ed59c5
LP
3277 l = strlen(s);
3278 if (l < 2)
11ce3427
LP
3279 return strdup(s);
3280
97c4a07d 3281 if (strchr(quotes, s[0]) && s[l-1] == s[0])
11ce3427
LP
3282 return strndup(s+1, l-2);
3283
3284 return strdup(s);
3285}
3286
5f7c426e 3287char *normalize_env_assignment(const char *s) {
57f30678
LP
3288 _cleanup_free_ char *name = NULL, *value = NULL, *p = NULL;
3289 char *eq, *r;
5f7c426e 3290
57f30678
LP
3291 eq = strchr(s, '=');
3292 if (!eq) {
3293 char *t;
5f7c426e 3294
57f30678
LP
3295 r = strdup(s);
3296 if (!r)
5f7c426e
LP
3297 return NULL;
3298
57f30678
LP
3299 t = strstrip(r);
3300 if (t == r)
3301 return r;
3302
3303 memmove(r, t, strlen(t) + 1);
3304 return r;
5f7c426e
LP
3305 }
3306
57f30678
LP
3307 name = strndup(s, eq - s);
3308 if (!name)
5f7c426e
LP
3309 return NULL;
3310
57f30678
LP
3311 p = strdup(eq + 1);
3312 if (!p)
5f7c426e 3313 return NULL;
5f7c426e
LP
3314
3315 value = unquote(strstrip(p), QUOTES);
57f30678 3316 if (!value)
5f7c426e 3317 return NULL;
5f7c426e 3318
57f30678 3319 if (asprintf(&r, "%s=%s", strstrip(name), value) < 0)
5f7c426e
LP
3320 r = NULL;
3321
5f7c426e
LP
3322 return r;
3323}
3324
8e12a6ae 3325int wait_for_terminate(pid_t pid, siginfo_t *status) {
1968a360
LP
3326 siginfo_t dummy;
3327
2e78aa99 3328 assert(pid >= 1);
1968a360
LP
3329
3330 if (!status)
3331 status = &dummy;
2e78aa99
LP
3332
3333 for (;;) {
8e12a6ae
LP
3334 zero(*status);
3335
3336 if (waitid(P_PID, pid, status, WEXITED) < 0) {
2e78aa99
LP
3337
3338 if (errno == EINTR)
3339 continue;
3340
3341 return -errno;
3342 }
3343
3344 return 0;
3345 }
3346}
3347
97c4a07d
LP
3348int wait_for_terminate_and_warn(const char *name, pid_t pid) {
3349 int r;
3350 siginfo_t status;
3351
3352 assert(name);
3353 assert(pid > 1);
3354
d87be9b0
LP
3355 r = wait_for_terminate(pid, &status);
3356 if (r < 0) {
97c4a07d
LP
3357 log_warning("Failed to wait for %s: %s", name, strerror(-r));
3358 return r;
3359 }
3360
3361 if (status.si_code == CLD_EXITED) {
3362 if (status.si_status != 0) {
3363 log_warning("%s failed with error code %i.", name, status.si_status);
0a27cf3f 3364 return status.si_status;
97c4a07d
LP
3365 }
3366
3367 log_debug("%s succeeded.", name);
3368 return 0;
3369
3370 } else if (status.si_code == CLD_KILLED ||
3371 status.si_code == CLD_DUMPED) {
3372
3373 log_warning("%s terminated by signal %s.", name, signal_to_string(status.si_status));
3374 return -EPROTO;
3375 }
3376
3377 log_warning("%s failed due to unknown reason.", name);
3378 return -EPROTO;
97c4a07d
LP
3379}
3380
919ce0b7 3381noreturn void freeze(void) {
720ce21d
LP
3382
3383 /* Make sure nobody waits for us on a socket anymore */
3384 close_all_fds(NULL, 0);
3385
c29597a1
LP
3386 sync();
3387
3c14d26c
LP
3388 for (;;)
3389 pause();
3390}
3391
00dc5d76
LP
3392bool null_or_empty(struct stat *st) {
3393 assert(st);
3394
3395 if (S_ISREG(st->st_mode) && st->st_size <= 0)
3396 return true;
3397
c8f26f42 3398 if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
00dc5d76
LP
3399 return true;
3400
3401 return false;
3402}
3403
83096483
LP
3404int null_or_empty_path(const char *fn) {
3405 struct stat st;
3406
3407 assert(fn);
3408
3409 if (stat(fn, &st) < 0)
3410 return -errno;
3411
3412 return null_or_empty(&st);
3413}
3414
a247755d 3415DIR *xopendirat(int fd, const char *name, int flags) {
c4731d11
LP
3416 int nfd;
3417 DIR *d;
3418
dd94c17e
LP
3419 assert(!(flags & O_CREAT));
3420
3421 nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
73836c5c 3422 if (nfd < 0)
c4731d11
LP
3423 return NULL;
3424
73836c5c
LP
3425 d = fdopendir(nfd);
3426 if (!d) {
c4731d11
LP
3427 close_nointr_nofail(nfd);
3428 return NULL;
3429 }
3430
3431 return d;
3b63d2d3
LP
3432}
3433
8a0867d6
LP
3434int signal_from_string_try_harder(const char *s) {
3435 int signo;
3436 assert(s);
3437
73836c5c
LP
3438 signo = signal_from_string(s);
3439 if (signo <= 0)
8a0867d6
LP
3440 if (startswith(s, "SIG"))
3441 return signal_from_string(s+3);
3442
3443 return signo;
3444}
3445
383182b5 3446static char *tag_to_udev_node(const char *tagvalue, const char *by) {
22f5f628
DR
3447 _cleanup_free_ char *t = NULL, *u = NULL;
3448 char *dn;
3449 size_t enc_len;
e23a0ce8 3450
383182b5
DR
3451 u = unquote(tagvalue, "\"\'");
3452 if (u == NULL)
3453 return NULL;
e23a0ce8 3454
1d5989fd 3455 enc_len = strlen(u) * 4 + 1;
22f5f628 3456 t = new(char, enc_len);
383182b5
DR
3457 if (t == NULL)
3458 return NULL;
e23a0ce8 3459
8f6ce71f 3460 if (encode_devnode_name(u, t, enc_len) < 0)
22f5f628 3461 return NULL;
e23a0ce8 3462
22f5f628 3463 if (asprintf(&dn, "/dev/disk/by-%s/%s", by, t) < 0)
383182b5 3464 return NULL;
e23a0ce8 3465
383182b5
DR
3466 return dn;
3467}
e23a0ce8 3468
383182b5 3469char *fstab_node_to_udev_node(const char *p) {
faa368e3
LP
3470 assert(p);
3471
383182b5
DR
3472 if (startswith(p, "LABEL="))
3473 return tag_to_udev_node(p+6, "label");
e23a0ce8 3474
383182b5
DR
3475 if (startswith(p, "UUID="))
3476 return tag_to_udev_node(p+5, "uuid");
e23a0ce8 3477
84cc2abf
DR
3478 if (startswith(p, "PARTUUID="))
3479 return tag_to_udev_node(p+9, "partuuid");
3480
3481 if (startswith(p, "PARTLABEL="))
3482 return tag_to_udev_node(p+10, "partlabel");
3483
e23a0ce8
LP
3484 return strdup(p);
3485}
3486
f212ac12
LP
3487bool tty_is_vc(const char *tty) {
3488 assert(tty);
3489
3490 if (startswith(tty, "/dev/"))
3491 tty += 5;
3492
98a28fef
LP
3493 return vtnr_from_tty(tty) >= 0;
3494}
3495
d1122ad5
LP
3496bool tty_is_console(const char *tty) {
3497 assert(tty);
3498
3499 if (startswith(tty, "/dev/"))
3500 tty += 5;
3501
3502 return streq(tty, "console");
3503}
3504
98a28fef
LP
3505int vtnr_from_tty(const char *tty) {
3506 int i, r;
3507
3508 assert(tty);
3509
3510 if (startswith(tty, "/dev/"))
3511 tty += 5;
3512
3513 if (!startswith(tty, "tty") )
3514 return -EINVAL;
3515
3516 if (tty[3] < '0' || tty[3] > '9')
3517 return -EINVAL;
3518
3519 r = safe_atoi(tty+3, &i);
3520 if (r < 0)
3521 return r;
3522
3523 if (i < 0 || i > 63)
3524 return -EINVAL;
3525
3526 return i;
f212ac12
LP
3527}
3528
21baf21a
MS
3529char *resolve_dev_console(char **active) {
3530 char *tty;
3531
3532 /* Resolve where /dev/console is pointing to, if /sys is actually ours
3533 * (i.e. not read-only-mounted which is a sign for container setups) */
3534
3535 if (path_is_read_only_fs("/sys") > 0)
3536 return NULL;
3537
3538 if (read_one_line_file("/sys/class/tty/console/active", active) < 0)
3539 return NULL;
3540
3541 /* If multiple log outputs are configured the last one is what
3542 * /dev/console points to */
3543 tty = strrchr(*active, ' ');
3544 if (tty)
3545 tty++;
3546 else
3547 tty = *active;
3548
8aa5429a
OB
3549 if (streq(tty, "tty0")) {
3550 char *tmp;
3551
3552 /* Get the active VC (e.g. tty1) */
3553 if (read_one_line_file("/sys/class/tty/tty0/active", &tmp) >= 0) {
3554 free(*active);
3555 tty = *active = tmp;
3556 }
3557 }
3558
21baf21a
MS
3559 return tty;
3560}
3561
3043935f 3562bool tty_is_vc_resolve(const char *tty) {
9588bc32 3563 _cleanup_free_ char *active = NULL;
3030ccd7 3564
e3aa71c3
LP
3565 assert(tty);
3566
3567 if (startswith(tty, "/dev/"))
3568 tty += 5;
3569
21baf21a
MS
3570 if (streq(tty, "console")) {
3571 tty = resolve_dev_console(&active);
3572 if (!tty)
3573 return false;
3574 }
3030ccd7 3575
9588bc32 3576 return tty_is_vc(tty);
3043935f
LP
3577}
3578
3579const char *default_term_for_tty(const char *tty) {
3580 assert(tty);
3581
acda6a05 3582 return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt102";
e3aa71c3
LP
3583}
3584
87d2c1ff 3585bool dirent_is_file(const struct dirent *de) {
fb19a739
LP
3586 assert(de);
3587
3588 if (ignore_file(de->d_name))
3589 return false;
3590
3591 if (de->d_type != DT_REG &&
3592 de->d_type != DT_LNK &&
3593 de->d_type != DT_UNKNOWN)
3594 return false;
3595
3596 return true;
3597}
3598
87d2c1ff
LP
3599bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) {
3600 assert(de);
3601
a228a22f
LP
3602 if (de->d_type != DT_REG &&
3603 de->d_type != DT_LNK &&
3604 de->d_type != DT_UNKNOWN)
3605 return false;
3606
3607 if (ignore_file_allow_backup(de->d_name))
87d2c1ff
LP
3608 return false;
3609
3610 return endswith(de->d_name, suffix);
3611}
3612
83cc030f
LP
3613void execute_directory(const char *directory, DIR *d, char *argv[]) {
3614 DIR *_d = NULL;
3615 struct dirent *de;
3616 Hashmap *pids = NULL;
3617
3618 assert(directory);
3619
650001c6
JJ
3620 /* Executes all binaries in a directory in parallel and
3621 * waits for them to finish. */
83cc030f
LP
3622
3623 if (!d) {
3624 if (!(_d = opendir(directory))) {
3625
3626 if (errno == ENOENT)
3627 return;
3628
3629 log_error("Failed to enumerate directory %s: %m", directory);
3630 return;
3631 }
3632
3633 d = _d;
3634 }
3635
3636 if (!(pids = hashmap_new(trivial_hash_func, trivial_compare_func))) {
3637 log_error("Failed to allocate set.");
3638 goto finish;
3639 }
3640
3641 while ((de = readdir(d))) {
3642 char *path;
3643 pid_t pid;
3644 int k;
3645
fb19a739 3646 if (!dirent_is_file(de))
83cc030f
LP
3647 continue;
3648
3649 if (asprintf(&path, "%s/%s", directory, de->d_name) < 0) {
0d0f0c50 3650 log_oom();
83cc030f
LP
3651 continue;
3652 }
3653
3654 if ((pid = fork()) < 0) {
3655 log_error("Failed to fork: %m");
3656 free(path);
3657 continue;
3658 }
3659
3660 if (pid == 0) {
3661 char *_argv[2];
3662 /* Child */
3663
3664 if (!argv) {
3665 _argv[0] = path;
3666 _argv[1] = NULL;
3667 argv = _argv;
3668 } else
6edd7d0a 3669 argv[0] = path;
83cc030f
LP
3670
3671 execv(path, argv);
3672
3673 log_error("Failed to execute %s: %m", path);
3674 _exit(EXIT_FAILURE);
3675 }
3676
3677 log_debug("Spawned %s as %lu", path, (unsigned long) pid);
3678
3679 if ((k = hashmap_put(pids, UINT_TO_PTR(pid), path)) < 0) {
3680 log_error("Failed to add PID to set: %s", strerror(-k));
3681 free(path);
3682 }
3683 }
3684
3685 while (!hashmap_isempty(pids)) {
ec3f9b53 3686 pid_t pid = PTR_TO_UINT(hashmap_first_key(pids));
b92bea5d 3687 siginfo_t si = {};
83cc030f
LP
3688 char *path;
3689
ec3f9b53 3690 if (waitid(P_PID, pid, &si, WEXITED) < 0) {
83cc030f
LP
3691
3692 if (errno == EINTR)
3693 continue;
3694
3695 log_error("waitid() failed: %m");
3696 goto finish;
3697 }
3698
3699 if ((path = hashmap_remove(pids, UINT_TO_PTR(si.si_pid)))) {
96342de6 3700 if (!is_clean_exit(si.si_code, si.si_status, NULL)) {
83cc030f
LP
3701 if (si.si_code == CLD_EXITED)
3702 log_error("%s exited with exit status %i.", path, si.si_status);
3703 else
3704 log_error("%s terminated by signal %s.", path, signal_to_string(si.si_status));
3705 } else
3706 log_debug("%s exited successfully.", path);
3707
3708 free(path);
3709 }
3710 }
3711
3712finish:
3713 if (_d)
3714 closedir(_d);
3715
3716 if (pids)
3717 hashmap_free_free(pids);
3718}
3719
430c18ed
LP
3720int kill_and_sigcont(pid_t pid, int sig) {
3721 int r;
3722
3723 r = kill(pid, sig) < 0 ? -errno : 0;
3724
3725 if (r >= 0)
3726 kill(pid, SIGCONT);
3727
3728 return r;
3729}
3730
05feefe0
LP
3731bool nulstr_contains(const char*nulstr, const char *needle) {
3732 const char *i;
3733
3734 if (!nulstr)
3735 return false;
3736
3737 NULSTR_FOREACH(i, nulstr)
3738 if (streq(i, needle))
3739 return true;
3740
3741 return false;
3742}
3743
6faa1114 3744bool plymouth_running(void) {
9408a2d2 3745 return access("/run/plymouth/pid", F_OK) >= 0;
6faa1114
LP
3746}
3747
9beb3f4d
LP
3748char* strshorten(char *s, size_t l) {
3749 assert(s);
3750
3751 if (l < strlen(s))
3752 s[l] = 0;
3753
3754 return s;
3755}
3756
3757static bool hostname_valid_char(char c) {
3758 return
3759 (c >= 'a' && c <= 'z') ||
3760 (c >= 'A' && c <= 'Z') ||
3761 (c >= '0' && c <= '9') ||
3762 c == '-' ||
3763 c == '_' ||
3764 c == '.';
3765}
3766
3767bool hostname_is_valid(const char *s) {
3768 const char *p;
aa3c5cf8 3769 bool dot;
9beb3f4d
LP
3770
3771 if (isempty(s))
3772 return false;
3773
aa3c5cf8
LP
3774 for (p = s, dot = true; *p; p++) {
3775 if (*p == '.') {
3776 if (dot)
3777 return false;
3778
3779 dot = true;
3780 } else {
3781 if (!hostname_valid_char(*p))
3782 return false;
3783
3784 dot = false;
3785 }
3786 }
3787
3788 if (dot)
3789 return false;
9beb3f4d
LP
3790
3791 if (p-s > HOST_NAME_MAX)
3792 return false;
3793
3794 return true;
3795}
3796
e724b063 3797char* hostname_cleanup(char *s, bool lowercase) {
9beb3f4d 3798 char *p, *d;
cec4ead9
LP
3799 bool dot;
3800
3801 for (p = s, d = s, dot = true; *p; p++) {
3802 if (*p == '.') {
e724b063 3803 if (dot)
cec4ead9 3804 continue;
9beb3f4d 3805
e724b063 3806 *(d++) = '.';
cec4ead9 3807 dot = true;
e724b063
LP
3808 } else if (hostname_valid_char(*p)) {
3809 *(d++) = lowercase ? tolower(*p) : *p;
cec4ead9 3810 dot = false;
e724b063 3811 }
cec4ead9 3812
cec4ead9 3813 }
9beb3f4d 3814
e724b063
LP
3815 if (dot && d > s)
3816 d[-1] = 0;
3817 else
3818 *d = 0;
3819
9beb3f4d 3820 strshorten(s, HOST_NAME_MAX);
cec4ead9 3821
9beb3f4d
LP
3822 return s;
3823}
3824
1325aa42 3825int pipe_eof(int fd) {
1325aa42 3826 int r;
b92bea5d
ZJS
3827 struct pollfd pollfd = {
3828 .fd = fd,
3829 .events = POLLIN|POLLHUP,
3830 };
1325aa42
LP
3831
3832 r = poll(&pollfd, 1, 0);
3833 if (r < 0)
3834 return -errno;
3835
3836 if (r == 0)
3837 return 0;
3838
3839 return pollfd.revents & POLLHUP;
3840}
3841
8f2d43a0 3842int fd_wait_for_event(int fd, int event, usec_t t) {
968d3d24 3843
b92bea5d
ZJS
3844 struct pollfd pollfd = {
3845 .fd = fd,
3846 .events = event,
3847 };
df50185b 3848
968d3d24
LP
3849 struct timespec ts;
3850 int r;
3851
3852 r = ppoll(&pollfd, 1, t == (usec_t) -1 ? NULL : timespec_store(&ts, t), NULL);
df50185b
LP
3853 if (r < 0)
3854 return -errno;
3855
3856 if (r == 0)
3857 return 0;
3858
3859 return pollfd.revents;
3860}
3861
5a3ab509
LP
3862int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
3863 FILE *f;
3864 char *t;
3865 const char *fn;
3866 size_t k;
3867 int fd;
3868
3869 assert(path);
3870 assert(_f);
3871 assert(_temp_path);
3872
3873 t = new(char, strlen(path) + 1 + 6 + 1);
3874 if (!t)
3875 return -ENOMEM;
3876
2b6bf07d
ZJS
3877 fn = basename(path);
3878 k = fn - path;
5a3ab509
LP
3879 memcpy(t, path, k);
3880 t[k] = '.';
3881 stpcpy(stpcpy(t+k+1, fn), "XXXXXX");
3882
3883 fd = mkostemp(t, O_WRONLY|O_CLOEXEC);
3884 if (fd < 0) {
3885 free(t);
3886 return -errno;
3887 }
3888
3889 f = fdopen(fd, "we");
3890 if (!f) {
3891 unlink(t);
3892 free(t);
3893 return -errno;
3894 }
3895
3896 *_f = f;
3897 *_temp_path = t;
3898
3899 return 0;
3900}
3901
6ea832a2 3902int terminal_vhangup_fd(int fd) {
5a3ab509
LP
3903 assert(fd >= 0);
3904
6ea832a2
LP
3905 if (ioctl(fd, TIOCVHANGUP) < 0)
3906 return -errno;
3907
3908 return 0;
3909}
3910
3911int terminal_vhangup(const char *name) {
3912 int fd, r;
3913
3914 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
3915 if (fd < 0)
3916 return fd;
3917
3918 r = terminal_vhangup_fd(fd);
3919 close_nointr_nofail(fd);
3920
3921 return r;
3922}
3923
3924int vt_disallocate(const char *name) {
3925 int fd, r;
3926 unsigned u;
6ea832a2
LP
3927
3928 /* Deallocate the VT if possible. If not possible
3929 * (i.e. because it is the active one), at least clear it
3930 * entirely (including the scrollback buffer) */
3931
b83bc4e9
LP
3932 if (!startswith(name, "/dev/"))
3933 return -EINVAL;
3934
3935 if (!tty_is_vc(name)) {
3936 /* So this is not a VT. I guess we cannot deallocate
3937 * it then. But let's at least clear the screen */
3938
3939 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
3940 if (fd < 0)
3941 return fd;
3942
8585357a
LP
3943 loop_write(fd,
3944 "\033[r" /* clear scrolling region */
3945 "\033[H" /* move home */
3946 "\033[2J", /* clear screen */
3947 10, false);
b83bc4e9
LP
3948 close_nointr_nofail(fd);
3949
3950 return 0;
3951 }
6ea832a2
LP
3952
3953 if (!startswith(name, "/dev/tty"))
3954 return -EINVAL;
3955
3956 r = safe_atou(name+8, &u);
3957 if (r < 0)
3958 return r;
3959
3960 if (u <= 0)
b83bc4e9 3961 return -EINVAL;
6ea832a2 3962
b83bc4e9 3963 /* Try to deallocate */
6ea832a2
LP
3964 fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
3965 if (fd < 0)
3966 return fd;
3967
3968 r = ioctl(fd, VT_DISALLOCATE, u);
b83bc4e9 3969 close_nointr_nofail(fd);
6ea832a2 3970
b83bc4e9
LP
3971 if (r >= 0)
3972 return 0;
6ea832a2 3973
b83bc4e9 3974 if (errno != EBUSY)
6ea832a2 3975 return -errno;
6ea832a2 3976
b83bc4e9
LP
3977 /* Couldn't deallocate, so let's clear it fully with
3978 * scrollback */
3979 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
6ea832a2 3980 if (fd < 0)
b83bc4e9 3981 return fd;
6ea832a2 3982
8585357a
LP
3983 loop_write(fd,
3984 "\033[r" /* clear scrolling region */
3985 "\033[H" /* move home */
3986 "\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */
3987 10, false);
b83bc4e9 3988 close_nointr_nofail(fd);
6ea832a2 3989
b83bc4e9 3990 return 0;
6ea832a2
LP
3991}
3992
51045322
LP
3993int copy_file(const char *from, const char *to, int flags) {
3994 _cleanup_close_ int fdf = -1;
3995 int r, fdt;
34ca941c
LP
3996
3997 assert(from);
3998 assert(to);
3999
4000 fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY);
4001 if (fdf < 0)
4002 return -errno;
4003
51045322
LP
4004 fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0644);
4005 if (fdt < 0)
34ca941c 4006 return -errno;
34ca941c
LP
4007
4008 for (;;) {
4009 char buf[PIPE_BUF];
4010 ssize_t n, k;
4011
4012 n = read(fdf, buf, sizeof(buf));
4013 if (n < 0) {
4014 r = -errno;
4015
34ca941c
LP
4016 close_nointr(fdt);
4017 unlink(to);
4018
4019 return r;
4020 }
4021
4022 if (n == 0)
4023 break;
4024
4025 errno = 0;
4026 k = loop_write(fdt, buf, n, false);
4027 if (n != k) {
4028 r = k < 0 ? k : (errno ? -errno : -EIO);
4029
34ca941c 4030 close_nointr(fdt);
34ca941c 4031 unlink(to);
51045322 4032
34ca941c
LP
4033 return r;
4034 }
4035 }
4036
34ca941c
LP
4037 r = close_nointr(fdt);
4038
4039 if (r < 0) {
4040 unlink(to);
4041 return r;
4042 }
4043
4044 return 0;
4045}
4046
424a19f8
LP
4047int symlink_atomic(const char *from, const char *to) {
4048 char *x;
4049 _cleanup_free_ char *t;
34ca941c
LP
4050 const char *fn;
4051 size_t k;
9bf3b535 4052 uint64_t u;
34ca941c
LP
4053 unsigned i;
4054 int r;
4055
4056 assert(from);
4057 assert(to);
4058
4059 t = new(char, strlen(to) + 1 + 16 + 1);
4060 if (!t)
4061 return -ENOMEM;
4062
2b6bf07d 4063 fn = basename(to);
34ca941c
LP
4064 k = fn-to;
4065 memcpy(t, to, k);
4066 t[k] = '.';
4067 x = stpcpy(t+k+1, fn);
4068
9bf3b535 4069 u = random_u64();
34ca941c 4070 for (i = 0; i < 16; i++) {
9bf3b535
LP
4071 *(x++) = hexchar(u & 0xF);
4072 u >>= 4;
34ca941c
LP
4073 }
4074
4075 *x = 0;
4076
424a19f8
LP
4077 if (symlink(from, t) < 0)
4078 return -errno;
34ca941c
LP
4079
4080 if (rename(t, to) < 0) {
4081 r = -errno;
4082 unlink(t);
34ca941c
LP
4083 return r;
4084 }
4085
424a19f8 4086 return 0;
34ca941c
LP
4087}
4088
4d6d6518
LP
4089bool display_is_local(const char *display) {
4090 assert(display);
4091
4092 return
4093 display[0] == ':' &&
4094 display[1] >= '0' &&
4095 display[1] <= '9';
4096}
4097
4098int socket_from_display(const char *display, char **path) {
4099 size_t k;
4100 char *f, *c;
4101
4102 assert(display);
4103 assert(path);
4104
4105 if (!display_is_local(display))
4106 return -EINVAL;
4107
4108 k = strspn(display+1, "0123456789");
4109
4110 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
4111 if (!f)
4112 return -ENOMEM;
4113
4114 c = stpcpy(f, "/tmp/.X11-unix/X");
4115 memcpy(c, display+1, k);
4116 c[k] = 0;
4117
4118 *path = f;
4119
4120 return 0;
4121}
4122
d05c5031
LP
4123int get_user_creds(
4124 const char **username,
4125 uid_t *uid, gid_t *gid,
4126 const char **home,
4127 const char **shell) {
4128
1cccf435 4129 struct passwd *p;
ddd88763 4130 uid_t u;
1cccf435
MV
4131
4132 assert(username);
4133 assert(*username);
1cccf435
MV
4134
4135 /* We enforce some special rules for uid=0: in order to avoid
4136 * NSS lookups for root we hardcode its data. */
4137
4138 if (streq(*username, "root") || streq(*username, "0")) {
4139 *username = "root";
4b67834e
LP
4140
4141 if (uid)
4142 *uid = 0;
4143
4144 if (gid)
4145 *gid = 0;
4146
4147 if (home)
4148 *home = "/root";
d05c5031
LP
4149
4150 if (shell)
4151 *shell = "/bin/sh";
4152
1cccf435
MV
4153 return 0;
4154 }
4155
ddd88763 4156 if (parse_uid(*username, &u) >= 0) {
1cccf435 4157 errno = 0;
ddd88763 4158 p = getpwuid(u);
1cccf435
MV
4159
4160 /* If there are multiple users with the same id, make
4161 * sure to leave $USER to the configured value instead
4162 * of the first occurrence in the database. However if
4163 * the uid was configured by a numeric uid, then let's
4164 * pick the real username from /etc/passwd. */
4165 if (p)
4166 *username = p->pw_name;
4167 } else {
4168 errno = 0;
4169 p = getpwnam(*username);
4170 }
4171
4172 if (!p)
8333c77e 4173 return errno > 0 ? -errno : -ESRCH;
1cccf435 4174
4b67834e
LP
4175 if (uid)
4176 *uid = p->pw_uid;
4177
4178 if (gid)
4179 *gid = p->pw_gid;
4180
4181 if (home)
4182 *home = p->pw_dir;
4183
d05c5031
LP
4184 if (shell)
4185 *shell = p->pw_shell;
4186
4b67834e
LP
4187 return 0;
4188}
4189
59164be4
LP
4190char* uid_to_name(uid_t uid) {
4191 struct passwd *p;
4192 char *r;
4193
4194 if (uid == 0)
4195 return strdup("root");
4196
4197 p = getpwuid(uid);
4198 if (p)
4199 return strdup(p->pw_name);
4200
4201 if (asprintf(&r, "%lu", (unsigned long) uid) < 0)
4202 return NULL;
4203
4204 return r;
4205}
4206
4468addc
LP
4207char* gid_to_name(gid_t gid) {
4208 struct group *p;
4209 char *r;
4210
4211 if (gid == 0)
4212 return strdup("root");
4213
4214 p = getgrgid(gid);
4215 if (p)
4216 return strdup(p->gr_name);
4217
4218 if (asprintf(&r, "%lu", (unsigned long) gid) < 0)
4219 return NULL;
4220
4221 return r;
4222}
4223
4b67834e
LP
4224int get_group_creds(const char **groupname, gid_t *gid) {
4225 struct group *g;
4226 gid_t id;
4227
4228 assert(groupname);
4229
4230 /* We enforce some special rules for gid=0: in order to avoid
4231 * NSS lookups for root we hardcode its data. */
4232
4233 if (streq(*groupname, "root") || streq(*groupname, "0")) {
4234 *groupname = "root";
4235
4236 if (gid)
4237 *gid = 0;
4238
4239 return 0;
4240 }
4241
4242 if (parse_gid(*groupname, &id) >= 0) {
4243 errno = 0;
4244 g = getgrgid(id);
4245
4246 if (g)
4247 *groupname = g->gr_name;
4248 } else {
4249 errno = 0;
4250 g = getgrnam(*groupname);
4251 }
4252
4253 if (!g)
8333c77e 4254 return errno > 0 ? -errno : -ESRCH;
4b67834e
LP
4255
4256 if (gid)
4257 *gid = g->gr_gid;
4258
1cccf435
MV
4259 return 0;
4260}
4261
4468addc
LP
4262int in_gid(gid_t gid) {
4263 gid_t *gids;
43673799
LP
4264 int ngroups_max, r, i;
4265
43673799
LP
4266 if (getgid() == gid)
4267 return 1;
4268
4269 if (getegid() == gid)
4270 return 1;
4271
4272 ngroups_max = sysconf(_SC_NGROUPS_MAX);
4273 assert(ngroups_max > 0);
4274
4275 gids = alloca(sizeof(gid_t) * ngroups_max);
4276
4277 r = getgroups(ngroups_max, gids);
4278 if (r < 0)
4279 return -errno;
4280
4281 for (i = 0; i < r; i++)
4282 if (gids[i] == gid)
4283 return 1;
4284
4285 return 0;
4286}
4287
4468addc
LP
4288int in_group(const char *name) {
4289 int r;
4290 gid_t gid;
4291
4292 r = get_group_creds(&name, &gid);
4293 if (r < 0)
4294 return r;
4295
4296 return in_gid(gid);
4297}
4298
8092a428 4299int glob_exists(const char *path) {
7fd1b19b 4300 _cleanup_globfree_ glob_t g = {};
8d98da3f 4301 int k;
8092a428
LP
4302
4303 assert(path);
4304
8092a428
LP
4305 errno = 0;
4306 k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
4307
4308 if (k == GLOB_NOMATCH)
8d98da3f 4309 return 0;
8092a428 4310 else if (k == GLOB_NOSPACE)
8d98da3f 4311 return -ENOMEM;
8092a428 4312 else if (k == 0)
8d98da3f 4313 return !strv_isempty(g.gl_pathv);
8092a428 4314 else
8d98da3f
ZJS
4315 return errno ? -errno : -EIO;
4316}
8092a428 4317
8d98da3f
ZJS
4318int glob_extend(char ***strv, const char *path) {
4319 _cleanup_globfree_ glob_t g = {};
4320 int k;
4321 char **p;
4322
4323 errno = 0;
a8ccacf5 4324 k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
8d98da3f
ZJS
4325
4326 if (k == GLOB_NOMATCH)
4327 return -ENOENT;
4328 else if (k == GLOB_NOSPACE)
4329 return -ENOMEM;
4330 else if (k != 0 || strv_isempty(g.gl_pathv))
4331 return errno ? -errno : -EIO;
4332
4333 STRV_FOREACH(p, g.gl_pathv) {
4334 k = strv_extend(strv, *p);
4335 if (k < 0)
4336 break;
4337 }
4338
4339 return k;
8092a428
LP
4340}
4341
83096483
LP
4342int dirent_ensure_type(DIR *d, struct dirent *de) {
4343 struct stat st;
4344
4345 assert(d);
4346 assert(de);
4347
4348 if (de->d_type != DT_UNKNOWN)
4349 return 0;
4350
4351 if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
4352 return -errno;
4353
4354 de->d_type =
4355 S_ISREG(st.st_mode) ? DT_REG :
4356 S_ISDIR(st.st_mode) ? DT_DIR :
4357 S_ISLNK(st.st_mode) ? DT_LNK :
4358 S_ISFIFO(st.st_mode) ? DT_FIFO :
4359 S_ISSOCK(st.st_mode) ? DT_SOCK :
4360 S_ISCHR(st.st_mode) ? DT_CHR :
4361 S_ISBLK(st.st_mode) ? DT_BLK :
4362 DT_UNKNOWN;
4363
4364 return 0;
4365}
4366
4367int in_search_path(const char *path, char **search) {
893fa014
ZJS
4368 char **i;
4369 _cleanup_free_ char *parent = NULL;
83096483
LP
4370 int r;
4371
9eb977db 4372 r = path_get_parent(path, &parent);
83096483
LP
4373 if (r < 0)
4374 return r;
4375
893fa014
ZJS
4376 STRV_FOREACH(i, search)
4377 if (path_equal(parent, *i))
4378 return 1;
83096483 4379
893fa014 4380 return 0;
83096483
LP
4381}
4382
034a2a52 4383int get_files_in_directory(const char *path, char ***list) {
893fa014
ZJS
4384 _cleanup_closedir_ DIR *d = NULL;
4385 size_t bufsize = 0, n = 0;
4386 _cleanup_strv_free_ char **l = NULL;
034a2a52
LP
4387
4388 assert(path);
d60ef526
LP
4389
4390 /* Returns all files in a directory in *list, and the number
4391 * of files as return value. If list is NULL returns only the
893fa014 4392 * number. */
034a2a52
LP
4393
4394 d = opendir(path);
8ea913b2
LP
4395 if (!d)
4396 return -errno;
4397
034a2a52 4398 for (;;) {
7d5e9c0f 4399 struct dirent *de;
034a2a52 4400
3fd11280
FW
4401 errno = 0;
4402 de = readdir(d);
4403 if (!de && errno != 0)
4404 return -errno;
034a2a52
LP
4405 if (!de)
4406 break;
4407
4408 dirent_ensure_type(d, de);
4409
4410 if (!dirent_is_file(de))
4411 continue;
4412
d60ef526 4413 if (list) {
893fa014
ZJS
4414 /* one extra slot is needed for the terminating NULL */
4415 if (!GREEDY_REALLOC(l, bufsize, n + 2))
4416 return -ENOMEM;
034a2a52 4417
893fa014
ZJS
4418 l[n] = strdup(de->d_name);
4419 if (!l[n])
4420 return -ENOMEM;
034a2a52 4421
893fa014 4422 l[++n] = NULL;
d60ef526 4423 } else
893fa014 4424 n++;
034a2a52
LP
4425 }
4426
893fa014
ZJS
4427 if (list) {
4428 *list = l;
4429 l = NULL; /* avoid freeing */
4430 }
034a2a52 4431
893fa014 4432 return n;
034a2a52
LP
4433}
4434
b7def684 4435char *strjoin(const char *x, ...) {
911a4828
LP
4436 va_list ap;
4437 size_t l;
4438 char *r, *p;
4439
4440 va_start(ap, x);
4441
4442 if (x) {
4443 l = strlen(x);
4444
4445 for (;;) {
4446 const char *t;
040f18ea 4447 size_t n;
911a4828
LP
4448
4449 t = va_arg(ap, const char *);
4450 if (!t)
4451 break;
4452
040f18ea 4453 n = strlen(t);
e98055de
LN
4454 if (n > ((size_t) -1) - l) {
4455 va_end(ap);
040f18ea 4456 return NULL;
e98055de 4457 }
040f18ea
LP
4458
4459 l += n;
911a4828
LP
4460 }
4461 } else
4462 l = 0;
4463
4464 va_end(ap);
4465
4466 r = new(char, l+1);
4467 if (!r)
4468 return NULL;
4469
4470 if (x) {
4471 p = stpcpy(r, x);
4472
4473 va_start(ap, x);
4474
4475 for (;;) {
4476 const char *t;
4477
4478 t = va_arg(ap, const char *);
4479 if (!t)
4480 break;
4481
4482 p = stpcpy(p, t);
4483 }
8ea913b2
LP
4484
4485 va_end(ap);
911a4828
LP
4486 } else
4487 r[0] = 0;
4488
4489 return r;
4490}
4491
b636465b 4492bool is_main_thread(void) {
ec202eae 4493 static thread_local int cached = 0;
b636465b
LP
4494
4495 if (_unlikely_(cached == 0))
4496 cached = getpid() == gettid() ? 1 : -1;
4497
4498 return cached > 0;
4499}
4500
94959f0f
LP
4501int block_get_whole_disk(dev_t d, dev_t *ret) {
4502 char *p, *s;
4503 int r;
4504 unsigned n, m;
4505
4506 assert(ret);
4507
4508 /* If it has a queue this is good enough for us */
4509 if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0)
4510 return -ENOMEM;
4511
4512 r = access(p, F_OK);
4513 free(p);
4514
4515 if (r >= 0) {
4516 *ret = d;
4517 return 0;
4518 }
4519
4520 /* If it is a partition find the originating device */
4521 if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0)
4522 return -ENOMEM;
4523
4524 r = access(p, F_OK);
4525 free(p);
4526
4527 if (r < 0)
4528 return -ENOENT;
4529
4530 /* Get parent dev_t */
4531 if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0)
4532 return -ENOMEM;
4533
4534 r = read_one_line_file(p, &s);
4535 free(p);
4536
4537 if (r < 0)
4538 return r;
4539
4540 r = sscanf(s, "%u:%u", &m, &n);
4541 free(s);
4542
4543 if (r != 2)
4544 return -EINVAL;
4545
4546 /* Only return this if it is really good enough for us. */
4547 if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0)
4548 return -ENOMEM;
4549
4550 r = access(p, F_OK);
4551 free(p);
4552
4553 if (r >= 0) {
4554 *ret = makedev(m, n);
4555 return 0;
4556 }
4557
4558 return -ENOENT;
4559}
4560
8d53b453 4561int file_is_priv_sticky(const char *p) {
ad293f5a
LP
4562 struct stat st;
4563
4564 assert(p);
4565
4566 if (lstat(p, &st) < 0)
4567 return -errno;
4568
4569 return
8d53b453 4570 (st.st_uid == 0 || st.st_uid == getuid()) &&
ad293f5a
LP
4571 (st.st_mode & S_ISVTX);
4572}
94959f0f 4573
f41607a6
LP
4574static const char *const ioprio_class_table[] = {
4575 [IOPRIO_CLASS_NONE] = "none",
4576 [IOPRIO_CLASS_RT] = "realtime",
4577 [IOPRIO_CLASS_BE] = "best-effort",
4578 [IOPRIO_CLASS_IDLE] = "idle"
4579};
4580
f8b69d1d 4581DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX);
f41607a6
LP
4582
4583static const char *const sigchld_code_table[] = {
4584 [CLD_EXITED] = "exited",
4585 [CLD_KILLED] = "killed",
4586 [CLD_DUMPED] = "dumped",
4587 [CLD_TRAPPED] = "trapped",
4588 [CLD_STOPPED] = "stopped",
4589 [CLD_CONTINUED] = "continued",
4590};
4591
4592DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
4593
4594static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = {
4595 [LOG_FAC(LOG_KERN)] = "kern",
4596 [LOG_FAC(LOG_USER)] = "user",
4597 [LOG_FAC(LOG_MAIL)] = "mail",
4598 [LOG_FAC(LOG_DAEMON)] = "daemon",
4599 [LOG_FAC(LOG_AUTH)] = "auth",
4600 [LOG_FAC(LOG_SYSLOG)] = "syslog",
4601 [LOG_FAC(LOG_LPR)] = "lpr",
4602 [LOG_FAC(LOG_NEWS)] = "news",
4603 [LOG_FAC(LOG_UUCP)] = "uucp",
4604 [LOG_FAC(LOG_CRON)] = "cron",
4605 [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
4606 [LOG_FAC(LOG_FTP)] = "ftp",
4607 [LOG_FAC(LOG_LOCAL0)] = "local0",
4608 [LOG_FAC(LOG_LOCAL1)] = "local1",
4609 [LOG_FAC(LOG_LOCAL2)] = "local2",
4610 [LOG_FAC(LOG_LOCAL3)] = "local3",
4611 [LOG_FAC(LOG_LOCAL4)] = "local4",
4612 [LOG_FAC(LOG_LOCAL5)] = "local5",
4613 [LOG_FAC(LOG_LOCAL6)] = "local6",
4614 [LOG_FAC(LOG_LOCAL7)] = "local7"
4615};
4616
f8b69d1d 4617DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0));
f41607a6
LP
4618
4619static const char *const log_level_table[] = {
4620 [LOG_EMERG] = "emerg",
4621 [LOG_ALERT] = "alert",
4622 [LOG_CRIT] = "crit",
4623 [LOG_ERR] = "err",
4624 [LOG_WARNING] = "warning",
4625 [LOG_NOTICE] = "notice",
4626 [LOG_INFO] = "info",
4627 [LOG_DEBUG] = "debug"
4628};
4629
f8b69d1d 4630DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG);
f41607a6
LP
4631
4632static const char* const sched_policy_table[] = {
4633 [SCHED_OTHER] = "other",
4634 [SCHED_BATCH] = "batch",
4635 [SCHED_IDLE] = "idle",
4636 [SCHED_FIFO] = "fifo",
4637 [SCHED_RR] = "rr"
4638};
4639
f8b69d1d 4640DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
f41607a6
LP
4641
4642static const char* const rlimit_table[] = {
4643 [RLIMIT_CPU] = "LimitCPU",
4644 [RLIMIT_FSIZE] = "LimitFSIZE",
4645 [RLIMIT_DATA] = "LimitDATA",
4646 [RLIMIT_STACK] = "LimitSTACK",
4647 [RLIMIT_CORE] = "LimitCORE",
4648 [RLIMIT_RSS] = "LimitRSS",
4649 [RLIMIT_NOFILE] = "LimitNOFILE",
4650 [RLIMIT_AS] = "LimitAS",
4651 [RLIMIT_NPROC] = "LimitNPROC",
4652 [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
4653 [RLIMIT_LOCKS] = "LimitLOCKS",
4654 [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
4655 [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
4656 [RLIMIT_NICE] = "LimitNICE",
4657 [RLIMIT_RTPRIO] = "LimitRTPRIO",
4658 [RLIMIT_RTTIME] = "LimitRTTIME"
4659};
4660
4661DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
4662
4663static const char* const ip_tos_table[] = {
4664 [IPTOS_LOWDELAY] = "low-delay",
4665 [IPTOS_THROUGHPUT] = "throughput",
4666 [IPTOS_RELIABILITY] = "reliability",
4667 [IPTOS_LOWCOST] = "low-cost",
4668};
4669
f8b69d1d 4670DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
f41607a6 4671
4e240ab0 4672static const char *const __signal_table[] = {
f41607a6
LP
4673 [SIGHUP] = "HUP",
4674 [SIGINT] = "INT",
4675 [SIGQUIT] = "QUIT",
4676 [SIGILL] = "ILL",
4677 [SIGTRAP] = "TRAP",
4678 [SIGABRT] = "ABRT",
4679 [SIGBUS] = "BUS",
4680 [SIGFPE] = "FPE",
4681 [SIGKILL] = "KILL",
4682 [SIGUSR1] = "USR1",
4683 [SIGSEGV] = "SEGV",
4684 [SIGUSR2] = "USR2",
4685 [SIGPIPE] = "PIPE",
4686 [SIGALRM] = "ALRM",
4687 [SIGTERM] = "TERM",
4688#ifdef SIGSTKFLT
4689 [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */
4690#endif
4691 [SIGCHLD] = "CHLD",
4692 [SIGCONT] = "CONT",
4693 [SIGSTOP] = "STOP",
4694 [SIGTSTP] = "TSTP",
4695 [SIGTTIN] = "TTIN",
4696 [SIGTTOU] = "TTOU",
4697 [SIGURG] = "URG",
4698 [SIGXCPU] = "XCPU",
4699 [SIGXFSZ] = "XFSZ",
4700 [SIGVTALRM] = "VTALRM",
4701 [SIGPROF] = "PROF",
4702 [SIGWINCH] = "WINCH",
4703 [SIGIO] = "IO",
4704 [SIGPWR] = "PWR",
4705 [SIGSYS] = "SYS"
4706};
4707
4e240ab0
MS
4708DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
4709
4710const char *signal_to_string(int signo) {
ec202eae 4711 static thread_local char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1];
4e240ab0
MS
4712 const char *name;
4713
4714 name = __signal_to_string(signo);
4715 if (name)
4716 return name;
4717
4718 if (signo >= SIGRTMIN && signo <= SIGRTMAX)
fa70beaa 4719 snprintf(buf, sizeof(buf), "RTMIN+%d", signo - SIGRTMIN);
4e240ab0 4720 else
fa70beaa
LP
4721 snprintf(buf, sizeof(buf), "%d", signo);
4722
4e240ab0
MS
4723 return buf;
4724}
4725
4726int signal_from_string(const char *s) {
4727 int signo;
4728 int offset = 0;
4729 unsigned u;
4730
040f18ea 4731 signo = __signal_from_string(s);
4e240ab0
MS
4732 if (signo > 0)
4733 return signo;
4734
4735 if (startswith(s, "RTMIN+")) {
4736 s += 6;
4737 offset = SIGRTMIN;
4738 }
4739 if (safe_atou(s, &u) >= 0) {
4740 signo = (int) u + offset;
4741 if (signo > 0 && signo < _NSIG)
4742 return signo;
4743 }
4744 return -1;
4745}
65457142
FC
4746
4747bool kexec_loaded(void) {
4748 bool loaded = false;
4749 char *s;
4750
4751 if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) {
4752 if (s[0] == '1')
4753 loaded = true;
4754 free(s);
4755 }
4756 return loaded;
4757}
fb9de93d
LP
4758
4759int strdup_or_null(const char *a, char **b) {
4760 char *c;
4761
4762 assert(b);
4763
4764 if (!a) {
4765 *b = NULL;
4766 return 0;
4767 }
4768
4769 c = strdup(a);
4770 if (!c)
4771 return -ENOMEM;
4772
4773 *b = c;
4774 return 0;
4775}
64685e0c 4776
87d2c1ff
LP
4777int prot_from_flags(int flags) {
4778
4779 switch (flags & O_ACCMODE) {
4780
4781 case O_RDONLY:
4782 return PROT_READ;
4783
4784 case O_WRONLY:
4785 return PROT_WRITE;
4786
4787 case O_RDWR:
4788 return PROT_READ|PROT_WRITE;
4789
4790 default:
4791 return -EINVAL;
4792 }
7c99e0c1 4793}
689b9a22 4794
babfc091 4795char *format_bytes(char *buf, size_t l, off_t t) {
c0f99c21 4796 unsigned i;
babfc091
LP
4797
4798 static const struct {
4799 const char *suffix;
4800 off_t factor;
4801 } table[] = {
32895bb3
LP
4802 { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
4803 { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
babfc091
LP
4804 { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
4805 { "G", 1024ULL*1024ULL*1024ULL },
4806 { "M", 1024ULL*1024ULL },
4807 { "K", 1024ULL },
4808 };
4809
4810 for (i = 0; i < ELEMENTSOF(table); i++) {
4811
4812 if (t >= table[i].factor) {
4813 snprintf(buf, l,
4814 "%llu.%llu%s",
4815 (unsigned long long) (t / table[i].factor),
4816 (unsigned long long) (((t*10ULL) / table[i].factor) % 10ULL),
4817 table[i].suffix);
4818
4819 goto finish;
4820 }
4821 }
4822
4823 snprintf(buf, l, "%lluB", (unsigned long long) t);
4824
4825finish:
4826 buf[l-1] = 0;
4827 return buf;
4828
4829}
55d7bfc1
LP
4830
4831void* memdup(const void *p, size_t l) {
4832 void *r;
4833
4834 assert(p);
4835
4836 r = malloc(l);
4837 if (!r)
4838 return NULL;
4839
4840 memcpy(r, p, l);
4841 return r;
4842}
bb99a35a
LP
4843
4844int fd_inc_sndbuf(int fd, size_t n) {
4845 int r, value;
4846 socklen_t l = sizeof(value);
4847
4848 r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
92d75ca4 4849 if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
bb99a35a
LP
4850 return 0;
4851
92d75ca4
LP
4852 /* If we have the privileges we will ignore the kernel limit. */
4853
bb99a35a 4854 value = (int) n;
92d75ca4
LP
4855 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
4856 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
4857 return -errno;
bb99a35a
LP
4858
4859 return 1;
4860}
4861
4862int fd_inc_rcvbuf(int fd, size_t n) {
4863 int r, value;
4864 socklen_t l = sizeof(value);
4865
4866 r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l);
92d75ca4 4867 if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
bb99a35a
LP
4868 return 0;
4869
92d75ca4 4870 /* If we have the privileges we will ignore the kernel limit. */
bb99a35a 4871
92d75ca4
LP
4872 value = (int) n;
4873 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0)
4874 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
4875 return -errno;
bb99a35a
LP
4876 return 1;
4877}
6bb92a16 4878
9bdc770c 4879int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
6bb92a16
LP
4880 pid_t parent_pid, agent_pid;
4881 int fd;
4882 bool stdout_is_tty, stderr_is_tty;
4883 unsigned n, i;
4884 va_list ap;
4885 char **l;
4886
4887 assert(pid);
4888 assert(path);
4889
4890 parent_pid = getpid();
4891
4892 /* Spawns a temporary TTY agent, making sure it goes away when
4893 * we go away */
4894
4895 agent_pid = fork();
4896 if (agent_pid < 0)
4897 return -errno;
4898
4899 if (agent_pid != 0) {
4900 *pid = agent_pid;
4901 return 0;
4902 }
4903
4904 /* In the child:
4905 *
4906 * Make sure the agent goes away when the parent dies */
4907 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
4908 _exit(EXIT_FAILURE);
4909
4910 /* Check whether our parent died before we were able
4911 * to set the death signal */
4912 if (getppid() != parent_pid)
4913 _exit(EXIT_SUCCESS);
4914
4915 /* Don't leak fds to the agent */
9bdc770c 4916 close_all_fds(except, n_except);
6bb92a16
LP
4917
4918 stdout_is_tty = isatty(STDOUT_FILENO);
4919 stderr_is_tty = isatty(STDERR_FILENO);
4920
4921 if (!stdout_is_tty || !stderr_is_tty) {
4922 /* Detach from stdout/stderr. and reopen
4923 * /dev/tty for them. This is important to
4924 * ensure that when systemctl is started via
4925 * popen() or a similar call that expects to
4926 * read EOF we actually do generate EOF and
4927 * not delay this indefinitely by because we
4928 * keep an unused copy of stdin around. */
4929 fd = open("/dev/tty", O_WRONLY);
4930 if (fd < 0) {
4931 log_error("Failed to open /dev/tty: %m");
4932 _exit(EXIT_FAILURE);
4933 }
4934
4935 if (!stdout_is_tty)
4936 dup2(fd, STDOUT_FILENO);
4937
4938 if (!stderr_is_tty)
4939 dup2(fd, STDERR_FILENO);
4940
4941 if (fd > 2)
4942 close(fd);
4943 }
4944
4945 /* Count arguments */
4946 va_start(ap, path);
4947 for (n = 0; va_arg(ap, char*); n++)
4948 ;
4949 va_end(ap);
4950
4951 /* Allocate strv */
4952 l = alloca(sizeof(char *) * (n + 1));
4953
4954 /* Fill in arguments */
4955 va_start(ap, path);
4956 for (i = 0; i <= n; i++)
4957 l[i] = va_arg(ap, char*);
4958 va_end(ap);
4959
4960 execv(path, l);
4961 _exit(EXIT_FAILURE);
4962}
68faf98c
LP
4963
4964int setrlimit_closest(int resource, const struct rlimit *rlim) {
4965 struct rlimit highest, fixed;
4966
4967 assert(rlim);
4968
4969 if (setrlimit(resource, rlim) >= 0)
4970 return 0;
4971
4972 if (errno != EPERM)
4973 return -errno;
4974
4975 /* So we failed to set the desired setrlimit, then let's try
4976 * to get as close as we can */
4977 assert_se(getrlimit(resource, &highest) == 0);
4978
4979 fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max);
4980 fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max);
4981
4982 if (setrlimit(resource, &fixed) < 0)
4983 return -errno;
4984
4985 return 0;
4986}
3d9a4122 4987
ab94af92 4988int getenv_for_pid(pid_t pid, const char *field, char **_value) {
49aa47c7
LP
4989 _cleanup_fclose_ FILE *f = NULL;
4990 char *value = NULL;
ab94af92 4991 int r;
ab94af92
LP
4992 bool done = false;
4993 size_t l;
49aa47c7 4994 const char *path;
ab94af92 4995
49aa47c7 4996 assert(pid >= 0);
ab94af92
LP
4997 assert(field);
4998 assert(_value);
4999
b68fa010 5000 path = procfs_file_alloca(pid, "environ");
ab94af92
LP
5001
5002 f = fopen(path, "re");
5003 if (!f)
5004 return -errno;
5005
5006 l = strlen(field);
5007 r = 0;
5008
5009 do {
5010 char line[LINE_MAX];
5011 unsigned i;
5012
5013 for (i = 0; i < sizeof(line)-1; i++) {
5014 int c;
5015
5016 c = getc(f);
5017 if (_unlikely_(c == EOF)) {
5018 done = true;
5019 break;
5020 } else if (c == 0)
5021 break;
5022
5023 line[i] = c;
5024 }
5025 line[i] = 0;
5026
5027 if (memcmp(line, field, l) == 0 && line[l] == '=') {
5028 value = strdup(line + l + 1);
49aa47c7
LP
5029 if (!value)
5030 return -ENOMEM;
ab94af92
LP
5031
5032 r = 1;
5033 break;
5034 }
5035
5036 } while (!done);
5037
49aa47c7 5038 *_value = value;
ab94af92
LP
5039 return r;
5040}
d889a206 5041
49dbfa7b
LP
5042bool is_valid_documentation_url(const char *url) {
5043 assert(url);
5044
5045 if (startswith(url, "http://") && url[7])
5046 return true;
5047
5048 if (startswith(url, "https://") && url[8])
5049 return true;
5050
5051 if (startswith(url, "file:") && url[5])
5052 return true;
5053
5054 if (startswith(url, "info:") && url[5])
5055 return true;
5056
5057 if (startswith(url, "man:") && url[4])
5058 return true;
5059
5060 return false;
5061}
9be346c9
HH
5062
5063bool in_initrd(void) {
73020ab2 5064 static int saved = -1;
825c6fe5 5065 struct statfs s;
8f33b5b8 5066
825c6fe5
LP
5067 if (saved >= 0)
5068 return saved;
5069
5070 /* We make two checks here:
5071 *
5072 * 1. the flag file /etc/initrd-release must exist
5073 * 2. the root file system must be a memory file system
5074 *
5075 * The second check is extra paranoia, since misdetecting an
5076 * initrd can have bad bad consequences due the initrd
5077 * emptying when transititioning to the main systemd.
5078 */
5079
5080 saved = access("/etc/initrd-release", F_OK) >= 0 &&
5081 statfs("/", &s) >= 0 &&
943aad8c 5082 is_temporary_fs(&s);
9be346c9 5083
8f33b5b8 5084 return saved;
9be346c9 5085}
069cfc85
LP
5086
5087void warn_melody(void) {
e67f47e5 5088 _cleanup_close_ int fd = -1;
069cfc85
LP
5089
5090 fd = open("/dev/console", O_WRONLY|O_CLOEXEC|O_NOCTTY);
5091 if (fd < 0)
5092 return;
5093
040f18ea 5094 /* Yeah, this is synchronous. Kinda sucks. But well... */
069cfc85
LP
5095
5096 ioctl(fd, KIOCSOUND, (int)(1193180/440));
5097 usleep(125*USEC_PER_MSEC);
5098
5099 ioctl(fd, KIOCSOUND, (int)(1193180/220));
5100 usleep(125*USEC_PER_MSEC);
5101
5102 ioctl(fd, KIOCSOUND, (int)(1193180/220));
5103 usleep(125*USEC_PER_MSEC);
5104
5105 ioctl(fd, KIOCSOUND, 0);
069cfc85 5106}
cd3bd60a
LP
5107
5108int make_console_stdio(void) {
5109 int fd, r;
5110
5111 /* Make /dev/console the controlling terminal and stdin/stdout/stderr */
5112
5113 fd = acquire_terminal("/dev/console", false, true, true, (usec_t) -1);
5114 if (fd < 0) {
5115 log_error("Failed to acquire terminal: %s", strerror(-fd));
5116 return fd;
5117 }
5118
5119 r = make_stdio(fd);
5120 if (r < 0) {
5121 log_error("Failed to duplicate terminal fd: %s", strerror(-r));
5122 return r;
5123 }
5124
5125 return 0;
5126}
7c5f152a
LP
5127
5128int get_home_dir(char **_h) {
2cfbd749 5129 struct passwd *p;
7c5f152a 5130 const char *e;
2cfbd749 5131 char *h;
7c5f152a 5132 uid_t u;
7c5f152a
LP
5133
5134 assert(_h);
5135
5136 /* Take the user specified one */
5137 e = getenv("HOME");
5138 if (e) {
5139 h = strdup(e);
5140 if (!h)
5141 return -ENOMEM;
5142
5143 *_h = h;
5144 return 0;
5145 }
5146
5147 /* Hardcode home directory for root to avoid NSS */
5148 u = getuid();
5149 if (u == 0) {
5150 h = strdup("/root");
5151 if (!h)
5152 return -ENOMEM;
5153
5154 *_h = h;
5155 return 0;
5156 }
5157
5158 /* Check the database... */
5159 errno = 0;
5160 p = getpwuid(u);
5161 if (!p)
bcb161b0 5162 return errno > 0 ? -errno : -ESRCH;
7c5f152a
LP
5163
5164 if (!path_is_absolute(p->pw_dir))
5165 return -EINVAL;
5166
5167 h = strdup(p->pw_dir);
5168 if (!h)
5169 return -ENOMEM;
5170
5171 *_h = h;
5172 return 0;
5173}
5174
2cfbd749
LP
5175int get_shell(char **_s) {
5176 struct passwd *p;
5177 const char *e;
5178 char *s;
5179 uid_t u;
5180
5181 assert(_s);
5182
5183 /* Take the user specified one */
5184 e = getenv("SHELL");
5185 if (e) {
5186 s = strdup(e);
5187 if (!s)
5188 return -ENOMEM;
5189
5190 *_s = s;
5191 return 0;
5192 }
5193
5194 /* Hardcode home directory for root to avoid NSS */
5195 u = getuid();
5196 if (u == 0) {
5197 s = strdup("/bin/sh");
5198 if (!s)
5199 return -ENOMEM;
5200
5201 *_s = s;
5202 return 0;
5203 }
5204
5205 /* Check the database... */
5206 errno = 0;
5207 p = getpwuid(u);
5208 if (!p)
5209 return errno > 0 ? -errno : -ESRCH;
5210
5211 if (!path_is_absolute(p->pw_shell))
5212 return -EINVAL;
5213
5214 s = strdup(p->pw_shell);
5215 if (!s)
5216 return -ENOMEM;
5217
5218 *_s = s;
5219 return 0;
5220}
5221
0b507b17
LP
5222bool filename_is_safe(const char *p) {
5223
5224 if (isempty(p))
5225 return false;
5226
5227 if (strchr(p, '/'))
5228 return false;
5229
5230 if (streq(p, "."))
5231 return false;
5232
5233 if (streq(p, ".."))
5234 return false;
5235
5236 if (strlen(p) > FILENAME_MAX)
5237 return false;
5238
5239 return true;
5240}
5241
5242bool string_is_safe(const char *p) {
5243 const char *t;
5244
5245 assert(p);
5246
5247 for (t = p; *t; t++) {
01539d6e 5248 if (*t > 0 && *t < ' ')
0b507b17
LP
5249 return false;
5250
011afa76 5251 if (strchr("\\\"\'", *t))
0b507b17
LP
5252 return false;
5253 }
5254
5255 return true;
5256}
cfbc22ab 5257
ac4c8d6d
ZJS
5258/**
5259 * Check if a string contains control characters.
5260 * Spaces and tabs are not considered control characters.
5261 */
4d1a6904
LP
5262bool string_has_cc(const char *p) {
5263 const char *t;
5264
5265 assert(p);
5266
5267 for (t = p; *t; t++)
da2620a5 5268 if (*t > 0 && *t < ' ' && *t != '\t')
4d1a6904
LP
5269 return true;
5270
5271 return false;
5272}
5273
e884315e
LP
5274bool path_is_safe(const char *p) {
5275
5276 if (isempty(p))
5277 return false;
5278
5279 if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
5280 return false;
5281
5282 if (strlen(p) > PATH_MAX)
5283 return false;
5284
5285 /* The following two checks are not really dangerous, but hey, they still are confusing */
5286 if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./"))
5287 return false;
5288
5289 if (strstr(p, "//"))
5290 return false;
5291
5292 return true;
5293}
5294
a9e12476
KS
5295/* hey glibc, APIs with callbacks without a user pointer are so useless */
5296void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
1c574591 5297 int (*compar) (const void *, const void *, void *), void *arg) {
a9e12476
KS
5298 size_t l, u, idx;
5299 const void *p;
5300 int comparison;
5301
5302 l = 0;
5303 u = nmemb;
5304 while (l < u) {
5305 idx = (l + u) / 2;
5306 p = (void *)(((const char *) base) + (idx * size));
5307 comparison = compar(key, p, arg);
5308 if (comparison < 0)
5309 u = idx;
5310 else if (comparison > 0)
5311 l = idx + 1;
5312 else
5313 return (void *)p;
5314 }
5315 return NULL;
5316}
09017585
MS
5317
5318bool is_locale_utf8(void) {
5319 const char *set;
5320 static int cached_answer = -1;
5321
5322 if (cached_answer >= 0)
5323 goto out;
5324
5325 if (!setlocale(LC_ALL, "")) {
5326 cached_answer = true;
5327 goto out;
5328 }
5329
5330 set = nl_langinfo(CODESET);
5331 if (!set) {
5332 cached_answer = true;
5333 goto out;
5334 }
5335
f168c273 5336 if (streq(set, "UTF-8")) {
fee79e01
HH
5337 cached_answer = true;
5338 goto out;
5339 }
5340
6cf2f1d9
HH
5341 /* For LC_CTYPE=="C" return true, because CTYPE is effectly
5342 * unset and everything can do to UTF-8 nowadays. */
fee79e01
HH
5343 set = setlocale(LC_CTYPE, NULL);
5344 if (!set) {
5345 cached_answer = true;
5346 goto out;
5347 }
5348
6cf2f1d9
HH
5349 /* Check result, but ignore the result if C was set
5350 * explicitly. */
5351 cached_answer =
5352 streq(set, "C") &&
5353 !getenv("LC_ALL") &&
5354 !getenv("LC_CTYPE") &&
5355 !getenv("LANG");
fee79e01 5356
09017585 5357out:
6cf2f1d9 5358 return (bool) cached_answer;
09017585 5359}
c339d977
MS
5360
5361const char *draw_special_char(DrawSpecialChar ch) {
5362 static const char *draw_table[2][_DRAW_SPECIAL_CHAR_MAX] = {
5363 /* UTF-8 */ {
45a5ff0d
MS
5364 [DRAW_TREE_VERT] = "\342\224\202 ", /* │ */
5365 [DRAW_TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */
5366 [DRAW_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */
55c0b89c 5367 [DRAW_TREE_SPACE] = " ", /* */
45a5ff0d 5368 [DRAW_TRIANGULAR_BULLET] = "\342\200\243 ", /* ‣ */
3deadb91 5369 [DRAW_BLACK_CIRCLE] = "\342\227\217 ", /* ● */
c339d977
MS
5370 },
5371 /* ASCII fallback */ {
45a5ff0d
MS
5372 [DRAW_TREE_VERT] = "| ",
5373 [DRAW_TREE_BRANCH] = "|-",
5374 [DRAW_TREE_RIGHT] = "`-",
55c0b89c 5375 [DRAW_TREE_SPACE] = " ",
45a5ff0d 5376 [DRAW_TRIANGULAR_BULLET] = "> ",
3deadb91 5377 [DRAW_BLACK_CIRCLE] = "* ",
c339d977
MS
5378 }
5379 };
5380
5381 return draw_table[!is_locale_utf8()][ch];
5382}
409bc9c3
LP
5383
5384char *strreplace(const char *text, const char *old_string, const char *new_string) {
5385 const char *f;
5386 char *t, *r;
5387 size_t l, old_len, new_len;
5388
5389 assert(text);
5390 assert(old_string);
5391 assert(new_string);
5392
5393 old_len = strlen(old_string);
5394 new_len = strlen(new_string);
5395
5396 l = strlen(text);
5397 r = new(char, l+1);
5398 if (!r)
5399 return NULL;
5400
5401 f = text;
5402 t = r;
5403 while (*f) {
5404 char *a;
5405 size_t d, nl;
5406
5407 if (!startswith(f, old_string)) {
5408 *(t++) = *(f++);
5409 continue;
5410 }
5411
5412 d = t - r;
5413 nl = l - old_len + new_len;
5414 a = realloc(r, nl + 1);
5415 if (!a)
5416 goto oom;
5417
5418 l = nl;
5419 r = a;
5420 t = r + d;
5421
5422 t = stpcpy(t, new_string);
5423 f += old_len;
5424 }
5425
5426 *t = 0;
5427 return r;
5428
5429oom:
5430 free(r);
5431 return NULL;
5432}
e8bc0ea2
LP
5433
5434char *strip_tab_ansi(char **ibuf, size_t *_isz) {
660ddc72 5435 const char *i, *begin = NULL;
e8bc0ea2
LP
5436 enum {
5437 STATE_OTHER,
5438 STATE_ESCAPE,
5439 STATE_BRACKET
5440 } state = STATE_OTHER;
5441 char *obuf = NULL;
5442 size_t osz = 0, isz;
5443 FILE *f;
5444
5445 assert(ibuf);
5446 assert(*ibuf);
5447
5448 /* Strips ANSI color and replaces TABs by 8 spaces */
5449
5450 isz = _isz ? *_isz : strlen(*ibuf);
5451
5452 f = open_memstream(&obuf, &osz);
5453 if (!f)
5454 return NULL;
5455
5456 for (i = *ibuf; i < *ibuf + isz + 1; i++) {
5457
5458 switch (state) {
5459
5460 case STATE_OTHER:
5461 if (i >= *ibuf + isz) /* EOT */
5462 break;
5463 else if (*i == '\x1B')
5464 state = STATE_ESCAPE;
5465 else if (*i == '\t')
5466 fputs(" ", f);
5467 else
5468 fputc(*i, f);
5469 break;
5470
5471 case STATE_ESCAPE:
5472 if (i >= *ibuf + isz) { /* EOT */
5473 fputc('\x1B', f);
5474 break;
5475 } else if (*i == '[') {
5476 state = STATE_BRACKET;
5477 begin = i + 1;
5478 } else {
5479 fputc('\x1B', f);
5480 fputc(*i, f);
5481 state = STATE_OTHER;
5482 }
5483
5484 break;
5485
5486 case STATE_BRACKET:
5487
5488 if (i >= *ibuf + isz || /* EOT */
5489 (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) {
5490 fputc('\x1B', f);
5491 fputc('[', f);
5492 state = STATE_OTHER;
5493 i = begin-1;
5494 } else if (*i == 'm')
5495 state = STATE_OTHER;
5496 break;
5497 }
5498 }
5499
5500 if (ferror(f)) {
5501 fclose(f);
5502 free(obuf);
5503 return NULL;
5504 }
5505
5506 fclose(f);
5507
5508 free(*ibuf);
5509 *ibuf = obuf;
5510
5511 if (_isz)
5512 *_isz = osz;
5513
5514 return obuf;
5515}
240dbaa4
LP
5516
5517int on_ac_power(void) {
5518 bool found_offline = false, found_online = false;
5519 _cleanup_closedir_ DIR *d = NULL;
5520
5521 d = opendir("/sys/class/power_supply");
5522 if (!d)
5523 return -errno;
5524
5525 for (;;) {
5526 struct dirent *de;
240dbaa4
LP
5527 _cleanup_close_ int fd = -1, device = -1;
5528 char contents[6];
5529 ssize_t n;
240dbaa4 5530
3fd11280
FW
5531 errno = 0;
5532 de = readdir(d);
5533 if (!de && errno != 0)
5534 return -errno;
240dbaa4
LP
5535
5536 if (!de)
5537 break;
5538
5539 if (ignore_file(de->d_name))
5540 continue;
5541
5542 device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
5543 if (device < 0) {
5544 if (errno == ENOENT || errno == ENOTDIR)
5545 continue;
5546
5547 return -errno;
5548 }
5549
5550 fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
5551 if (fd < 0) {
5552 if (errno == ENOENT)
5553 continue;
5554
5555 return -errno;
5556 }
5557
5558 n = read(fd, contents, sizeof(contents));
5559 if (n < 0)
5560 return -errno;
5561
5562 if (n != 6 || memcmp(contents, "Mains\n", 6))
5563 continue;
5564
5565 close_nointr_nofail(fd);
5566 fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
5567 if (fd < 0) {
5568 if (errno == ENOENT)
5569 continue;
5570
5571 return -errno;
5572 }
5573
5574 n = read(fd, contents, sizeof(contents));
5575 if (n < 0)
5576 return -errno;
5577
5578 if (n != 2 || contents[1] != '\n')
5579 return -EIO;
5580
5581 if (contents[0] == '1') {
5582 found_online = true;
5583 break;
5584 } else if (contents[0] == '0')
5585 found_offline = true;
5586 else
5587 return -EIO;
5588 }
5589
5590 return found_online || !found_offline;
5591}
fabe5c0e
LP
5592
5593static int search_and_fopen_internal(const char *path, const char *mode, char **search, FILE **_f) {
5594 char **i;
5595
5596 assert(path);
5597 assert(mode);
5598 assert(_f);
5599
5600 if (!path_strv_canonicalize_uniq(search))
5601 return -ENOMEM;
5602
5603 STRV_FOREACH(i, search) {
5604 _cleanup_free_ char *p = NULL;
5605 FILE *f;
5606
5607 p = strjoin(*i, "/", path, NULL);
5608 if (!p)
5609 return -ENOMEM;
5610
5611 f = fopen(p, mode);
5612 if (f) {
5613 *_f = f;
5614 return 0;
5615 }
5616
5617 if (errno != ENOENT)
5618 return -errno;
5619 }
5620
5621 return -ENOENT;
5622}
5623
5624int search_and_fopen(const char *path, const char *mode, const char **search, FILE **_f) {
5625 _cleanup_strv_free_ char **copy = NULL;
5626
5627 assert(path);
5628 assert(mode);
5629 assert(_f);
5630
5631 if (path_is_absolute(path)) {
5632 FILE *f;
5633
5634 f = fopen(path, mode);
5635 if (f) {
5636 *_f = f;
5637 return 0;
5638 }
5639
5640 return -errno;
5641 }
5642
5643 copy = strv_copy((char**) search);
5644 if (!copy)
5645 return -ENOMEM;
5646
5647 return search_and_fopen_internal(path, mode, copy, _f);
5648}
5649
5650int search_and_fopen_nulstr(const char *path, const char *mode, const char *search, FILE **_f) {
5651 _cleanup_strv_free_ char **s = NULL;
5652
5653 if (path_is_absolute(path)) {
5654 FILE *f;
5655
5656 f = fopen(path, mode);
5657 if (f) {
5658 *_f = f;
5659 return 0;
5660 }
5661
5662 return -errno;
5663 }
5664
5665 s = strv_split_nulstr(search);
5666 if (!s)
5667 return -ENOMEM;
5668
5669 return search_and_fopen_internal(path, mode, s, _f);
5670}
c17ec25e 5671
66e35261
LP
5672char *strextend(char **x, ...) {
5673 va_list ap;
5674 size_t f, l;
5675 char *r, *p;
5676
5677 assert(x);
5678
5679 l = f = *x ? strlen(*x) : 0;
5680
5681 va_start(ap, x);
5682 for (;;) {
5683 const char *t;
5684 size_t n;
5685
5686 t = va_arg(ap, const char *);
5687 if (!t)
5688 break;
5689
5690 n = strlen(t);
5691 if (n > ((size_t) -1) - l) {
5692 va_end(ap);
5693 return NULL;
5694 }
5695
5696 l += n;
5697 }
5698 va_end(ap);
5699
5700 r = realloc(*x, l+1);
5701 if (!r)
5702 return NULL;
5703
5704 p = r + f;
5705
5706 va_start(ap, x);
5707 for (;;) {
5708 const char *t;
5709
5710 t = va_arg(ap, const char *);
5711 if (!t)
5712 break;
5713
5714 p = stpcpy(p, t);
5715 }
5716 va_end(ap);
5717
5718 *p = 0;
5719 *x = r;
5720
5721 return r + l;
5722}
9a17484d
LP
5723
5724char *strrep(const char *s, unsigned n) {
5725 size_t l;
5726 char *r, *p;
5727 unsigned i;
5728
5729 assert(s);
5730
5731 l = strlen(s);
5732 p = r = malloc(l * n + 1);
5733 if (!r)
5734 return NULL;
5735
5736 for (i = 0; i < n; i++)
5737 p = stpcpy(p, s);
5738
5739 *p = 0;
5740 return r;
5741}
392d5b37
LP
5742
5743void* greedy_realloc(void **p, size_t *allocated, size_t need) {
5744 size_t a;
5745 void *q;
5746
98088803 5747 assert(p);
e93c33d4
SL
5748 assert(allocated);
5749
392d5b37
LP
5750 if (*allocated >= need)
5751 return *p;
5752
9607d947 5753 a = MAX(64u, need * 2);
98088803
LP
5754
5755 /* check for overflows */
5756 if (a < need)
5757 return NULL;
5758
392d5b37
LP
5759 q = realloc(*p, a);
5760 if (!q)
5761 return NULL;
5762
5763 *p = q;
5764 *allocated = a;
5765 return q;
5766}
aa96c6cb 5767
4545a231 5768void* greedy_realloc0(void **p, size_t *allocated, size_t need) {
98088803 5769 size_t prev;
4545a231
DH
5770 uint8_t *q;
5771
98088803
LP
5772 assert(p);
5773 assert(allocated);
5774
5775 prev = *allocated;
5776
4545a231
DH
5777 q = greedy_realloc(p, allocated, need);
5778 if (!q)
5779 return NULL;
5780
5781 if (*allocated > prev)
5782 memset(&q[prev], 0, *allocated - prev);
5783
5784 return q;
5785}
5786
aa96c6cb
LP
5787bool id128_is_valid(const char *s) {
5788 size_t i, l;
5789
5790 l = strlen(s);
5791 if (l == 32) {
5792
5793 /* Simple formatted 128bit hex string */
5794
5795 for (i = 0; i < l; i++) {
5796 char c = s[i];
5797
5798 if (!(c >= '0' && c <= '9') &&
5799 !(c >= 'a' && c <= 'z') &&
5800 !(c >= 'A' && c <= 'Z'))
5801 return false;
5802 }
5803
5804 } else if (l == 36) {
5805
5806 /* Formatted UUID */
5807
5808 for (i = 0; i < l; i++) {
5809 char c = s[i];
5810
5811 if ((i == 8 || i == 13 || i == 18 || i == 23)) {
5812 if (c != '-')
5813 return false;
5814 } else {
5815 if (!(c >= '0' && c <= '9') &&
5816 !(c >= 'a' && c <= 'z') &&
5817 !(c >= 'A' && c <= 'Z'))
5818 return false;
5819 }
5820 }
5821
5822 } else
5823 return false;
5824
5825 return true;
5826}
7085053a
DW
5827
5828void parse_user_at_host(char *arg, char **user, char **host) {
5829 assert(arg);
5830 assert(user);
5831 assert(host);
5832
5833 *host = strchr(arg, '@');
5834 if (*host == NULL)
5835 *host = arg;
5836 else {
5837 *host[0]++ = '\0';
5838 *user = arg;
5839 }
5840}
d4ac85c6
LP
5841
5842int split_pair(const char *s, const char *sep, char **l, char **r) {
5843 char *x, *a, *b;
5844
5845 assert(s);
5846 assert(sep);
5847 assert(l);
5848 assert(r);
5849
5850 if (isempty(sep))
5851 return -EINVAL;
5852
5853 x = strstr(s, sep);
5854 if (!x)
5855 return -EINVAL;
5856
5857 a = strndup(s, x - s);
5858 if (!a)
5859 return -ENOMEM;
5860
5861 b = strdup(x + strlen(sep));
5862 if (!b) {
5863 free(a);
5864 return -ENOMEM;
5865 }
5866
5867 *l = a;
5868 *r = b;
5869
5870 return 0;
5871}
295edddf 5872
74df0fca 5873int shall_restore_state(void) {
295edddf
TG
5874 _cleanup_free_ char *line;
5875 char *w, *state;
295edddf 5876 size_t l;
74df0fca 5877 int r;
295edddf 5878
74df0fca
LP
5879 r = proc_cmdline(&line);
5880 if (r < 0)
5881 return r;
5882 if (r == 0) /* Container ... */
5883 return 1;
295edddf 5884
74df0fca 5885 FOREACH_WORD_QUOTED(w, l, line, state)
85ca9433 5886 if (l == 23 && strneq(w, "systemd.restore_state=0", 23))
74df0fca
LP
5887 return 0;
5888
5889 return 1;
5890}
5891
5892int proc_cmdline(char **ret) {
5893 int r;
5894
5895 if (detect_container(NULL) > 0) {
02bb6cda
LP
5896 char *buf, *p;
5897 size_t sz = 0;
5898
5899 r = read_full_file("/proc/1/cmdline", &buf, &sz);
5900 if (r < 0)
5901 return r;
5902
5903 for (p = buf; p + 1 < buf + sz; p++)
5904 if (*p == 0)
5905 *p = ' ';
5906
5907 *p = 0;
5908 *ret = buf;
5909 return 1;
295edddf
TG
5910 }
5911
74df0fca
LP
5912 r = read_one_line_file("/proc/cmdline", ret);
5913 if (r < 0)
5914 return r;
295edddf 5915
74df0fca 5916 return 1;
295edddf 5917}
bc9fd78c
LP
5918
5919int container_get_leader(const char *machine, pid_t *pid) {
5920 _cleanup_free_ char *s = NULL, *class = NULL;
5921 const char *p;
5922 pid_t leader;
5923 int r;
5924
5925 assert(machine);
5926 assert(pid);
5927
5928 p = strappenda("/run/systemd/machines/", machine);
5929 r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
5930 if (r == -ENOENT)
5931 return -EHOSTDOWN;
5932 if (r < 0)
5933 return r;
5934 if (!s)
5935 return -EIO;
5936
5937 if (!streq_ptr(class, "container"))
5938 return -EIO;
5939
5940 r = parse_pid(s, &leader);
5941 if (r < 0)
5942 return r;
5943 if (leader <= 1)
5944 return -EIO;
5945
5946 *pid = leader;
5947 return 0;
5948}
5949
a4475f57
LP
5950int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *root_fd) {
5951 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1;
5952 const char *pidns, *mntns, *root;
bc9fd78c
LP
5953 int rfd;
5954
5955 assert(pid >= 0);
a4475f57
LP
5956 assert(pidns_fd);
5957 assert(mntns_fd);
bc9fd78c
LP
5958 assert(root_fd);
5959
a4475f57
LP
5960 mntns = procfs_file_alloca(pid, "ns/mnt");
5961 mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
5962 if (mntnsfd < 0)
5963 return -errno;
5964
5965 pidns = procfs_file_alloca(pid, "ns/pid");
5966 pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
5967 if (pidnsfd < 0)
bc9fd78c
LP
5968 return -errno;
5969
5970 root = procfs_file_alloca(pid, "root");
5971 rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
5972 if (rfd < 0)
5973 return -errno;
5974
a4475f57
LP
5975 *pidns_fd = pidnsfd;
5976 *mntns_fd = mntnsfd;
bc9fd78c 5977 *root_fd = rfd;
a4475f57
LP
5978 pidnsfd = -1;
5979 mntnsfd = -1;
bc9fd78c
LP
5980
5981 return 0;
5982}
5983
a4475f57
LP
5984int namespace_enter(int pidns_fd, int mntns_fd, int root_fd) {
5985 assert(pidns_fd >= 0);
5986 assert(mntns_fd >= 0);
bc9fd78c
LP
5987 assert(root_fd >= 0);
5988
a4475f57
LP
5989 if (setns(pidns_fd, CLONE_NEWPID) < 0)
5990 return -errno;
5991
5992 if (setns(mntns_fd, CLONE_NEWNS) < 0)
bc9fd78c
LP
5993 return -errno;
5994
5995 if (fchdir(root_fd) < 0)
5996 return -errno;
5997
5998 if (chroot(".") < 0)
5999 return -errno;
6000
5e2b3214
LP
6001 if (setresgid(0, 0, 0) < 0)
6002 return -errno;
6003
6004 if (setresuid(0, 0, 0) < 0)
6005 return -errno;
6006
bc9fd78c
LP
6007 return 0;
6008}
bf108e55
LP
6009
6010bool pid_valid(pid_t pid) {
6011 if (pid <= 0)
6012 return false;
6013
6014 if (kill(pid, 0) >= 0)
6015 return true;
6016
6017 return errno != ESRCH;
6018}
eff05270
LP
6019
6020int getpeercred(int fd, struct ucred *ucred) {
6021 socklen_t n = sizeof(struct ucred);
6022 struct ucred u;
6023 int r;
6024
6025 assert(fd >= 0);
6026 assert(ucred);
6027
6028 r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n);
6029 if (r < 0)
6030 return -errno;
6031
6032 if (n != sizeof(struct ucred))
6033 return -EIO;
6034
6035 /* Check if the data is actually useful and not suppressed due
6036 * to namespacing issues */
6037 if (u.pid <= 0)
6038 return -ENODATA;
6039
6040 *ucred = u;
6041 return 0;
6042}
6043
6044int getpeersec(int fd, char **ret) {
6045 socklen_t n = 64;
6046 char *s;
6047 int r;
6048
6049 assert(fd >= 0);
6050 assert(ret);
6051
6052 s = new0(char, n);
6053 if (!s)
6054 return -ENOMEM;
6055
6056 r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
6057 if (r < 0) {
6058 free(s);
6059
6060 if (errno != ERANGE)
6061 return -errno;
6062
6063 s = new0(char, n);
6064 if (!s)
6065 return -ENOMEM;
6066
6067 r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
6068 if (r < 0) {
6069 free(s);
6070 return -errno;
6071 }
6072 }
6073
ae98841e
LP
6074 if (isempty(s)) {
6075 free(s);
6076 return -ENOTSUP;
6077 }
6078
eff05270
LP
6079 *ret = s;
6080 return 0;
6081}
8e33886e 6082
65b3903f
ZJS
6083int writev_safe(int fd, const struct iovec *w, int j) {
6084 for (int i = 0; i < j; i++) {
6085 size_t written = 0;
6086
6087 while (written < w[i].iov_len) {
6088 ssize_t r;
6089
6090 r = write(fd, (char*) w[i].iov_base + written, w[i].iov_len - written);
6091 if (r < 0 && errno != -EINTR)
6092 return -errno;
6093
6094 written += r;
6095 }
6096 }
6097
6098 return 0;
6099}
6100
6101int mkostemp_safe(char *pattern, int flags) {
6102 char *s = pattern + strlen(pattern) - 6;
6103 uint64_t tries = TMP_MAX;
6104 int randfd, fd, i;
6105
6106 assert(streq(s, "XXXXXX"));
6107
6108 randfd = open("/dev/urandom", O_RDONLY);
6109 if (randfd < 0)
6110 return -ENOSYS;
6111
6112 while (tries--) {
6113 fd = read(randfd, s, 6);
6114 if (fd == 0)
6115 return -ENOSYS;
6116
6117 for (i = 0; i < 6; i++)
6118 s[i] = ALPHANUMERICAL[(unsigned) s[i] % strlen(ALPHANUMERICAL)];
6119
6120 fd = open(pattern, flags|O_EXCL|O_CREAT, S_IRUSR|S_IWUSR);
6121 if (fd >= 0)
6122 return fd;
6123 if (!IN_SET(errno, EEXIST, EINTR))
6124 return -errno;
6125 }
6126
6127 return -EEXIST;
6128}
6129
8e33886e
ZJS
6130int open_tmpfile(const char *path, int flags) {
6131 int fd;
6132 char *p;
6133
6134#ifdef O_TMPFILE
6135 fd = open(path, flags|O_TMPFILE, S_IRUSR|S_IWUSR);
6136 if (fd >= 0)
6137 return fd;
6138#endif
6139 p = strappenda(path, "/systemd-tmp-XXXXXX");
6140
65b3903f 6141 fd = mkostemp_safe(p, O_RDWR|O_CLOEXEC);
8e33886e 6142 if (fd < 0)
65b3903f 6143 return fd;
8e33886e
ZJS
6144
6145 unlink(p);
6146 return fd;
6147}