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