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