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