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