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