]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/util.c
systemctl: filter and sort member pid of cgroup
[thirdparty/systemd.git] / src / util.c
CommitLineData
60918275
LP
1/*-*- Mode: C; c-basic-offset: 8 -*-*/
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
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
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
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
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>
60918275
LP
50
51#include "macro.h"
52#include "util.h"
1dccbe19
LP
53#include "ioprio.h"
54#include "missing.h"
a9f5d454 55#include "log.h"
65d2ebdc 56#include "strv.h"
60918275 57
e05797fb
LP
58bool streq_ptr(const char *a, const char *b) {
59
60 /* Like streq(), but tries to make sense of NULL pointers */
61
62 if (a && b)
63 return streq(a, b);
64
65 if (!a && !b)
66 return true;
67
68 return false;
69}
70
47be870b 71usec_t now(clockid_t clock_id) {
60918275
LP
72 struct timespec ts;
73
47be870b 74 assert_se(clock_gettime(clock_id, &ts) == 0);
60918275
LP
75
76 return timespec_load(&ts);
77}
78
63983207 79dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
871d7de4
LP
80 assert(ts);
81
82 ts->realtime = now(CLOCK_REALTIME);
83 ts->monotonic = now(CLOCK_MONOTONIC);
84
85 return ts;
86}
87
60918275
LP
88usec_t timespec_load(const struct timespec *ts) {
89 assert(ts);
90
91 return
92 (usec_t) ts->tv_sec * USEC_PER_SEC +
93 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
94}
95
96struct timespec *timespec_store(struct timespec *ts, usec_t u) {
97 assert(ts);
98
99 ts->tv_sec = (time_t) (u / USEC_PER_SEC);
100 ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
101
102 return ts;
103}
104
105usec_t timeval_load(const struct timeval *tv) {
106 assert(tv);
107
108 return
109 (usec_t) tv->tv_sec * USEC_PER_SEC +
110 (usec_t) tv->tv_usec;
111}
112
113struct timeval *timeval_store(struct timeval *tv, usec_t u) {
114 assert(tv);
115
116 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
117 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
118
119 return tv;
120}
121
122bool endswith(const char *s, const char *postfix) {
123 size_t sl, pl;
124
125 assert(s);
126 assert(postfix);
127
128 sl = strlen(s);
129 pl = strlen(postfix);
130
d4d0d4db
LP
131 if (pl == 0)
132 return true;
133
60918275
LP
134 if (sl < pl)
135 return false;
136
137 return memcmp(s + sl - pl, postfix, pl) == 0;
138}
139
140bool startswith(const char *s, const char *prefix) {
141 size_t sl, pl;
142
143 assert(s);
144 assert(prefix);
145
146 sl = strlen(s);
147 pl = strlen(prefix);
148
d4d0d4db
LP
149 if (pl == 0)
150 return true;
151
60918275
LP
152 if (sl < pl)
153 return false;
154
155 return memcmp(s, prefix, pl) == 0;
156}
157
3177a7fa
MAP
158bool startswith_no_case(const char *s, const char *prefix) {
159 size_t sl, pl;
160 unsigned i;
161
162 assert(s);
163 assert(prefix);
164
165 sl = strlen(s);
166 pl = strlen(prefix);
167
168 if (pl == 0)
169 return true;
170
171 if (sl < pl)
172 return false;
173
174 for(i = 0; i < pl; ++i) {
175 if (tolower(s[i]) != tolower(prefix[i]))
176 return false;
177 }
178
179 return true;
180}
181
79d6d816
LP
182bool first_word(const char *s, const char *word) {
183 size_t sl, wl;
184
185 assert(s);
186 assert(word);
187
188 sl = strlen(s);
189 wl = strlen(word);
190
191 if (sl < wl)
192 return false;
193
d4d0d4db
LP
194 if (wl == 0)
195 return true;
196
79d6d816
LP
197 if (memcmp(s, word, wl) != 0)
198 return false;
199
d4d0d4db
LP
200 return s[wl] == 0 ||
201 strchr(WHITESPACE, s[wl]);
79d6d816
LP
202}
203
42f4e3c4 204int close_nointr(int fd) {
60918275
LP
205 assert(fd >= 0);
206
207 for (;;) {
208 int r;
209
210 if ((r = close(fd)) >= 0)
211 return r;
212
213 if (errno != EINTR)
214 return r;
215 }
216}
85261803 217
85f136b5 218void close_nointr_nofail(int fd) {
80876c20 219 int saved_errno = errno;
85f136b5
LP
220
221 /* like close_nointr() but cannot fail, and guarantees errno
222 * is unchanged */
223
224 assert_se(close_nointr(fd) == 0);
80876c20
LP
225
226 errno = saved_errno;
85f136b5
LP
227}
228
5b6319dc
LP
229void close_many(const int fds[], unsigned n_fd) {
230 unsigned i;
231
232 for (i = 0; i < n_fd; i++)
233 close_nointr_nofail(fds[i]);
234}
235
85261803
LP
236int parse_boolean(const char *v) {
237 assert(v);
238
44d8db9e 239 if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
85261803 240 return 1;
44d8db9e 241 else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
85261803
LP
242 return 0;
243
244 return -EINVAL;
245}
246
3ba686c1
LP
247int parse_pid(const char *s, pid_t* ret_pid) {
248 unsigned long ul;
249 pid_t pid;
250 int r;
251
252 assert(s);
253 assert(ret_pid);
254
255 if ((r = safe_atolu(s, &ul)) < 0)
256 return r;
257
258 pid = (pid_t) ul;
259
260 if ((unsigned long) pid != ul)
261 return -ERANGE;
262
263 if (pid <= 0)
264 return -ERANGE;
265
266 *ret_pid = pid;
267 return 0;
268}
269
85261803
LP
270int safe_atou(const char *s, unsigned *ret_u) {
271 char *x = NULL;
034c6ed7 272 unsigned long l;
85261803
LP
273
274 assert(s);
275 assert(ret_u);
276
277 errno = 0;
278 l = strtoul(s, &x, 0);
279
280 if (!x || *x || errno)
281 return errno ? -errno : -EINVAL;
282
034c6ed7 283 if ((unsigned long) (unsigned) l != l)
85261803
LP
284 return -ERANGE;
285
286 *ret_u = (unsigned) l;
287 return 0;
288}
289
290int safe_atoi(const char *s, int *ret_i) {
291 char *x = NULL;
034c6ed7 292 long l;
85261803
LP
293
294 assert(s);
295 assert(ret_i);
296
297 errno = 0;
298 l = strtol(s, &x, 0);
299
300 if (!x || *x || errno)
301 return errno ? -errno : -EINVAL;
302
034c6ed7 303 if ((long) (int) l != l)
85261803
LP
304 return -ERANGE;
305
034c6ed7
LP
306 *ret_i = (int) l;
307 return 0;
308}
309
034c6ed7
LP
310int safe_atollu(const char *s, long long unsigned *ret_llu) {
311 char *x = NULL;
312 unsigned long long l;
313
314 assert(s);
315 assert(ret_llu);
316
317 errno = 0;
318 l = strtoull(s, &x, 0);
319
320 if (!x || *x || errno)
321 return errno ? -errno : -EINVAL;
322
323 *ret_llu = l;
324 return 0;
325}
326
327int safe_atolli(const char *s, long long int *ret_lli) {
328 char *x = NULL;
329 long long l;
330
331 assert(s);
332 assert(ret_lli);
333
334 errno = 0;
335 l = strtoll(s, &x, 0);
336
337 if (!x || *x || errno)
338 return errno ? -errno : -EINVAL;
339
340 *ret_lli = l;
85261803
LP
341 return 0;
342}
a41e8209 343
a41e8209 344/* Split a string into words. */
65d2ebdc 345char *split(const char *c, size_t *l, const char *separator, char **state) {
a41e8209
LP
346 char *current;
347
348 current = *state ? *state : (char*) c;
349
350 if (!*current || *c == 0)
351 return NULL;
352
65d2ebdc
LP
353 current += strspn(current, separator);
354 *l = strcspn(current, separator);
82919e3d
LP
355 *state = current+*l;
356
357 return (char*) current;
358}
359
034c6ed7
LP
360/* Split a string into words, but consider strings enclosed in '' and
361 * "" as words even if they include spaces. */
362char *split_quoted(const char *c, size_t *l, char **state) {
0bab36f2
LP
363 char *current, *e;
364 bool escaped = false;
034c6ed7
LP
365
366 current = *state ? *state : (char*) c;
367
368 if (!*current || *c == 0)
369 return NULL;
370
371 current += strspn(current, WHITESPACE);
372
373 if (*current == '\'') {
374 current ++;
034c6ed7 375
0bab36f2
LP
376 for (e = current; *e; e++) {
377 if (escaped)
378 escaped = false;
379 else if (*e == '\\')
380 escaped = true;
381 else if (*e == '\'')
382 break;
383 }
384
385 *l = e-current;
386 *state = *e == 0 ? e : e+1;
034c6ed7
LP
387 } else if (*current == '\"') {
388 current ++;
034c6ed7 389
0bab36f2
LP
390 for (e = current; *e; e++) {
391 if (escaped)
392 escaped = false;
393 else if (*e == '\\')
394 escaped = true;
395 else if (*e == '\"')
396 break;
397 }
398
399 *l = e-current;
400 *state = *e == 0 ? e : e+1;
034c6ed7 401 } else {
0bab36f2
LP
402 for (e = current; *e; e++) {
403 if (escaped)
404 escaped = false;
405 else if (*e == '\\')
406 escaped = true;
407 else if (strchr(WHITESPACE, *e))
408 break;
409 }
410 *l = e-current;
411 *state = e;
034c6ed7
LP
412 }
413
414 return (char*) current;
415}
416
65d2ebdc
LP
417char **split_path_and_make_absolute(const char *p) {
418 char **l;
419 assert(p);
420
421 if (!(l = strv_split(p, ":")))
422 return NULL;
423
424 if (!strv_path_make_absolute_cwd(l)) {
425 strv_free(l);
426 return NULL;
427 }
428
429 return l;
430}
431
034c6ed7
LP
432int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
433 int r;
434 FILE *f;
435 char fn[132], line[256], *p;
bb00e604 436 long unsigned ppid;
034c6ed7
LP
437
438 assert(pid >= 0);
439 assert(_ppid);
440
bb00e604 441 assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%lu/stat", (unsigned long) pid) < (int) (sizeof(fn)-1));
034c6ed7
LP
442 fn[sizeof(fn)-1] = 0;
443
444 if (!(f = fopen(fn, "r")))
445 return -errno;
446
447 if (!(fgets(line, sizeof(line), f))) {
448 r = -errno;
449 fclose(f);
450 return r;
451 }
452
453 fclose(f);
454
455 /* Let's skip the pid and comm fields. The latter is enclosed
456 * in () but does not escape any () in its value, so let's
457 * skip over it manually */
458
459 if (!(p = strrchr(line, ')')))
460 return -EIO;
461
462 p++;
463
464 if (sscanf(p, " "
465 "%*c " /* state */
bb00e604 466 "%lu ", /* ppid */
034c6ed7
LP
467 &ppid) != 1)
468 return -EIO;
469
bb00e604 470 if ((long unsigned) (pid_t) ppid != ppid)
034c6ed7
LP
471 return -ERANGE;
472
473 *_ppid = (pid_t) ppid;
474
475 return 0;
476}
477
478int write_one_line_file(const char *fn, const char *line) {
479 FILE *f;
480 int r;
481
482 assert(fn);
483 assert(line);
484
485 if (!(f = fopen(fn, "we")))
486 return -errno;
487
488 if (fputs(line, f) < 0) {
489 r = -errno;
490 goto finish;
491 }
492
493 r = 0;
494finish:
495 fclose(f);
496 return r;
497}
498
499int read_one_line_file(const char *fn, char **line) {
500 FILE *f;
501 int r;
11316633 502 char t[2048], *c;
034c6ed7
LP
503
504 assert(fn);
505 assert(line);
506
507 if (!(f = fopen(fn, "re")))
508 return -errno;
509
510 if (!(fgets(t, sizeof(t), f))) {
511 r = -errno;
512 goto finish;
513 }
514
515 if (!(c = strdup(t))) {
516 r = -ENOMEM;
517 goto finish;
518 }
519
520 *line = c;
521 r = 0;
522
523finish:
524 fclose(f);
525 return r;
526}
44d8db9e 527
7072ced8
LP
528char *truncate_nl(char *s) {
529 assert(s);
530
531 s[strcspn(s, NEWLINE)] = 0;
532 return s;
533}
534
535int get_process_name(pid_t pid, char **name) {
536 char *p;
537 int r;
538
539 assert(pid >= 1);
540 assert(name);
541
bb00e604 542 if (asprintf(&p, "/proc/%lu/comm", (unsigned long) pid) < 0)
7072ced8
LP
543 return -ENOMEM;
544
545 r = read_one_line_file(p, name);
546 free(p);
547
548 if (r < 0)
549 return r;
550
551 truncate_nl(*name);
552 return 0;
553}
554
c59760ee
LP
555int get_process_cmdline(pid_t pid, size_t max_length, char **line) {
556 char *p, *r, *k;
557 int c;
558 bool space = false;
559 size_t left;
560 FILE *f;
561
562 assert(pid >= 1);
563 assert(max_length > 0);
564 assert(line);
565
566 if (asprintf(&p, "/proc/%lu/cmdline", (unsigned long) pid) < 0)
567 return -ENOMEM;
568
569 f = fopen(p, "r");
570 free(p);
571
572 if (!f)
573 return -errno;
574
575 if (!(r = new(char, max_length))) {
576 fclose(f);
577 return -ENOMEM;
578 }
579
580 k = r;
581 left = max_length;
582 while ((c = getc(f)) != EOF) {
583
584 if (isprint(c)) {
585 if (space) {
586 if (left <= 4)
587 break;
588
589 *(k++) = ' ';
057fbb58 590 left--;
c59760ee
LP
591 space = false;
592 }
593
594 if (left <= 4)
595 break;
596
597 *(k++) = (char) c;
057fbb58 598 left--;
c59760ee
LP
599 } else
600 space = true;
601 }
602
603 if (left <= 4) {
604 size_t n = MIN(left-1, 3U);
605 memcpy(k, "...", n);
606 k[n] = 0;
607 } else
608 *k = 0;
609
610 fclose(f);
611
612 *line = r;
613 return 0;
614}
615
fab56fc5
LP
616char *strnappend(const char *s, const char *suffix, size_t b) {
617 size_t a;
44d8db9e
LP
618 char *r;
619
fab56fc5
LP
620 if (!s && !suffix)
621 return strdup("");
622
623 if (!s)
624 return strndup(suffix, b);
625
626 if (!suffix)
627 return strdup(s);
628
44d8db9e
LP
629 assert(s);
630 assert(suffix);
631
632 a = strlen(s);
44d8db9e
LP
633
634 if (!(r = new(char, a+b+1)))
635 return NULL;
636
637 memcpy(r, s, a);
638 memcpy(r+a, suffix, b);
639 r[a+b] = 0;
640
641 return r;
642}
87f0e418 643
fab56fc5
LP
644char *strappend(const char *s, const char *suffix) {
645 return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
646}
647
87f0e418
LP
648int readlink_malloc(const char *p, char **r) {
649 size_t l = 100;
650
651 assert(p);
652 assert(r);
653
654 for (;;) {
655 char *c;
656 ssize_t n;
657
658 if (!(c = new(char, l)))
659 return -ENOMEM;
660
661 if ((n = readlink(p, c, l-1)) < 0) {
662 int ret = -errno;
663 free(c);
664 return ret;
665 }
666
667 if ((size_t) n < l-1) {
668 c[n] = 0;
669 *r = c;
670 return 0;
671 }
672
673 free(c);
674 l *= 2;
675 }
676}
677
2c7108c4
LP
678int readlink_and_make_absolute(const char *p, char **r) {
679 char *target, *k;
680 int j;
681
682 assert(p);
683 assert(r);
684
685 if ((j = readlink_malloc(p, &target)) < 0)
686 return j;
687
688 k = file_in_same_dir(p, target);
689 free(target);
690
691 if (!k)
692 return -ENOMEM;
693
694 *r = k;
695 return 0;
696}
697
87f0e418
LP
698char *file_name_from_path(const char *p) {
699 char *r;
700
701 assert(p);
702
703 if ((r = strrchr(p, '/')))
704 return r + 1;
705
706 return (char*) p;
707}
0301abf4
LP
708
709bool path_is_absolute(const char *p) {
710 assert(p);
711
712 return p[0] == '/';
713}
714
715bool is_path(const char *p) {
716
717 return !!strchr(p, '/');
718}
719
720char *path_make_absolute(const char *p, const char *prefix) {
721 char *r;
722
723 assert(p);
724
65d2ebdc
LP
725 /* Makes every item in the list an absolute path by prepending
726 * the prefix, if specified and necessary */
727
0301abf4
LP
728 if (path_is_absolute(p) || !prefix)
729 return strdup(p);
730
731 if (asprintf(&r, "%s/%s", prefix, p) < 0)
732 return NULL;
733
734 return r;
735}
2a987ee8 736
65d2ebdc
LP
737char *path_make_absolute_cwd(const char *p) {
738 char *cwd, *r;
739
740 assert(p);
741
742 /* Similar to path_make_absolute(), but prefixes with the
743 * current working directory. */
744
745 if (path_is_absolute(p))
746 return strdup(p);
747
748 if (!(cwd = get_current_dir_name()))
749 return NULL;
750
751 r = path_make_absolute(p, cwd);
752 free(cwd);
753
754 return r;
755}
756
757char **strv_path_make_absolute_cwd(char **l) {
758 char **s;
759
760 /* Goes through every item in the string list and makes it
761 * absolute. This works in place and won't rollback any
762 * changes on failure. */
763
764 STRV_FOREACH(s, l) {
765 char *t;
766
767 if (!(t = path_make_absolute_cwd(*s)))
768 return NULL;
769
770 free(*s);
771 *s = t;
772 }
773
774 return l;
775}
776
c3f6d675
LP
777char **strv_path_canonicalize(char **l) {
778 char **s;
779 unsigned k = 0;
780 bool enomem = false;
781
782 if (strv_isempty(l))
783 return l;
784
785 /* Goes through every item in the string list and canonicalize
786 * the path. This works in place and won't rollback any
787 * changes on failure. */
788
789 STRV_FOREACH(s, l) {
790 char *t, *u;
791
792 t = path_make_absolute_cwd(*s);
793 free(*s);
794
795 if (!t) {
796 enomem = true;
797 continue;
798 }
799
800 errno = 0;
801 u = canonicalize_file_name(t);
802 free(t);
803
804 if (!u) {
805 if (errno == ENOMEM || !errno)
806 enomem = true;
807
808 continue;
809 }
810
811 l[k++] = u;
812 }
813
814 l[k] = NULL;
815
816 if (enomem)
817 return NULL;
818
819 return l;
820}
821
2a987ee8
LP
822int reset_all_signal_handlers(void) {
823 int sig;
824
825 for (sig = 1; sig < _NSIG; sig++) {
826 struct sigaction sa;
827
828 if (sig == SIGKILL || sig == SIGSTOP)
829 continue;
830
831 zero(sa);
832 sa.sa_handler = SIG_DFL;
431c32bf 833 sa.sa_flags = SA_RESTART;
2a987ee8
LP
834
835 /* On Linux the first two RT signals are reserved by
836 * glibc, and sigaction() will return EINVAL for them. */
837 if ((sigaction(sig, &sa, NULL) < 0))
838 if (errno != EINVAL)
839 return -errno;
840 }
841
8e274523 842 return 0;
2a987ee8 843}
4a72ff34
LP
844
845char *strstrip(char *s) {
846 char *e, *l = NULL;
847
848 /* Drops trailing whitespace. Modifies the string in
849 * place. Returns pointer to first non-space character */
850
851 s += strspn(s, WHITESPACE);
852
853 for (e = s; *e; e++)
854 if (!strchr(WHITESPACE, *e))
855 l = e;
856
857 if (l)
858 *(l+1) = 0;
859 else
860 *s = 0;
861
862 return s;
4a72ff34
LP
863}
864
ee9b5e01
LP
865char *delete_chars(char *s, const char *bad) {
866 char *f, *t;
867
868 /* Drops all whitespace, regardless where in the string */
869
870 for (f = s, t = s; *f; f++) {
871 if (strchr(bad, *f))
872 continue;
873
874 *(t++) = *f;
875 }
876
877 *t = 0;
878
879 return s;
880}
881
4a72ff34
LP
882char *file_in_same_dir(const char *path, const char *filename) {
883 char *e, *r;
884 size_t k;
885
886 assert(path);
887 assert(filename);
888
889 /* This removes the last component of path and appends
890 * filename, unless the latter is absolute anyway or the
891 * former isn't */
892
893 if (path_is_absolute(filename))
894 return strdup(filename);
895
896 if (!(e = strrchr(path, '/')))
897 return strdup(filename);
898
899 k = strlen(filename);
900 if (!(r = new(char, e-path+1+k+1)))
901 return NULL;
902
903 memcpy(r, path, e-path+1);
904 memcpy(r+(e-path)+1, filename, k+1);
905
906 return r;
907}
fb624d04 908
8c6db833
LP
909int safe_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid) {
910 struct stat st;
911
912 if (mkdir(path, mode) >= 0)
913 if (chmod_and_chown(path, mode, uid, gid) < 0)
914 return -errno;
915
916 if (lstat(path, &st) < 0)
917 return -errno;
918
919 if ((st.st_mode & 0777) != mode ||
920 st.st_uid != uid ||
921 st.st_gid != gid ||
922 !S_ISDIR(st.st_mode)) {
923 errno = EEXIST;
924 return -errno;
925 }
926
927 return 0;
928}
929
930
a9f5d454
LP
931int mkdir_parents(const char *path, mode_t mode) {
932 const char *p, *e;
933
934 assert(path);
935
936 /* Creates every parent directory in the path except the last
937 * component. */
938
939 p = path + strspn(path, "/");
940 for (;;) {
941 int r;
942 char *t;
943
944 e = p + strcspn(p, "/");
945 p = e + strspn(e, "/");
946
947 /* Is this the last component? If so, then we're
948 * done */
949 if (*p == 0)
950 return 0;
951
952 if (!(t = strndup(path, e - path)))
953 return -ENOMEM;
954
955 r = mkdir(t, mode);
956
957 free(t);
958
959 if (r < 0 && errno != EEXIST)
960 return -errno;
961 }
962}
963
bbd67135
LP
964int mkdir_p(const char *path, mode_t mode) {
965 int r;
966
967 /* Like mkdir -p */
968
969 if ((r = mkdir_parents(path, mode)) < 0)
970 return r;
971
972 if (mkdir(path, mode) < 0)
973 return -errno;
974
975 return 0;
976}
977
c32dd69b
LP
978int rmdir_parents(const char *path, const char *stop) {
979 size_t l;
980 int r = 0;
981
982 assert(path);
983 assert(stop);
984
985 l = strlen(path);
986
987 /* Skip trailing slashes */
988 while (l > 0 && path[l-1] == '/')
989 l--;
990
991 while (l > 0) {
992 char *t;
993
994 /* Skip last component */
995 while (l > 0 && path[l-1] != '/')
996 l--;
997
998 /* Skip trailing slashes */
999 while (l > 0 && path[l-1] == '/')
1000 l--;
1001
1002 if (l <= 0)
1003 break;
1004
1005 if (!(t = strndup(path, l)))
1006 return -ENOMEM;
1007
1008 if (path_startswith(stop, t)) {
1009 free(t);
1010 return 0;
1011 }
1012
1013 r = rmdir(t);
1014 free(t);
1015
1016 if (r < 0)
1017 if (errno != ENOENT)
1018 return -errno;
1019 }
1020
1021 return 0;
1022}
1023
1024
fb624d04
LP
1025char hexchar(int x) {
1026 static const char table[16] = "0123456789abcdef";
1027
1028 return table[x & 15];
1029}
4fe88d28
LP
1030
1031int unhexchar(char c) {
1032
1033 if (c >= '0' && c <= '9')
1034 return c - '0';
1035
1036 if (c >= 'a' && c <= 'f')
ea430986 1037 return c - 'a' + 10;
4fe88d28
LP
1038
1039 if (c >= 'A' && c <= 'F')
ea430986 1040 return c - 'A' + 10;
4fe88d28
LP
1041
1042 return -1;
1043}
1044
1045char octchar(int x) {
1046 return '0' + (x & 7);
1047}
1048
1049int unoctchar(char c) {
1050
1051 if (c >= '0' && c <= '7')
1052 return c - '0';
1053
1054 return -1;
1055}
1056
5af98f82
LP
1057char decchar(int x) {
1058 return '0' + (x % 10);
1059}
1060
1061int undecchar(char c) {
1062
1063 if (c >= '0' && c <= '9')
1064 return c - '0';
1065
1066 return -1;
1067}
1068
4fe88d28
LP
1069char *cescape(const char *s) {
1070 char *r, *t;
1071 const char *f;
1072
1073 assert(s);
1074
1075 /* Does C style string escaping. */
1076
1077 if (!(r = new(char, strlen(s)*4 + 1)))
1078 return NULL;
1079
1080 for (f = s, t = r; *f; f++)
1081
1082 switch (*f) {
1083
1084 case '\a':
1085 *(t++) = '\\';
1086 *(t++) = 'a';
1087 break;
1088 case '\b':
1089 *(t++) = '\\';
1090 *(t++) = 'b';
1091 break;
1092 case '\f':
1093 *(t++) = '\\';
1094 *(t++) = 'f';
1095 break;
1096 case '\n':
1097 *(t++) = '\\';
1098 *(t++) = 'n';
1099 break;
1100 case '\r':
1101 *(t++) = '\\';
1102 *(t++) = 'r';
1103 break;
1104 case '\t':
1105 *(t++) = '\\';
1106 *(t++) = 't';
1107 break;
1108 case '\v':
1109 *(t++) = '\\';
1110 *(t++) = 'v';
1111 break;
1112 case '\\':
1113 *(t++) = '\\';
1114 *(t++) = '\\';
1115 break;
1116 case '"':
1117 *(t++) = '\\';
1118 *(t++) = '"';
1119 break;
1120 case '\'':
1121 *(t++) = '\\';
1122 *(t++) = '\'';
1123 break;
1124
1125 default:
1126 /* For special chars we prefer octal over
1127 * hexadecimal encoding, simply because glib's
1128 * g_strescape() does the same */
1129 if ((*f < ' ') || (*f >= 127)) {
1130 *(t++) = '\\';
1131 *(t++) = octchar((unsigned char) *f >> 6);
1132 *(t++) = octchar((unsigned char) *f >> 3);
1133 *(t++) = octchar((unsigned char) *f);
1134 } else
1135 *(t++) = *f;
1136 break;
1137 }
1138
1139 *t = 0;
1140
1141 return r;
1142}
1143
6febfd0d 1144char *cunescape_length(const char *s, size_t length) {
4fe88d28
LP
1145 char *r, *t;
1146 const char *f;
1147
1148 assert(s);
1149
1150 /* Undoes C style string escaping */
1151
6febfd0d 1152 if (!(r = new(char, length+1)))
4fe88d28
LP
1153 return r;
1154
6febfd0d 1155 for (f = s, t = r; f < s + length; f++) {
4fe88d28
LP
1156
1157 if (*f != '\\') {
1158 *(t++) = *f;
1159 continue;
1160 }
1161
1162 f++;
1163
1164 switch (*f) {
1165
1166 case 'a':
1167 *(t++) = '\a';
1168 break;
1169 case 'b':
1170 *(t++) = '\b';
1171 break;
1172 case 'f':
1173 *(t++) = '\f';
1174 break;
1175 case 'n':
1176 *(t++) = '\n';
1177 break;
1178 case 'r':
1179 *(t++) = '\r';
1180 break;
1181 case 't':
1182 *(t++) = '\t';
1183 break;
1184 case 'v':
1185 *(t++) = '\v';
1186 break;
1187 case '\\':
1188 *(t++) = '\\';
1189 break;
1190 case '"':
1191 *(t++) = '"';
1192 break;
1193 case '\'':
1194 *(t++) = '\'';
1195 break;
1196
e167fb86
LP
1197 case 's':
1198 /* This is an extension of the XDG syntax files */
1199 *(t++) = ' ';
1200 break;
1201
4fe88d28
LP
1202 case 'x': {
1203 /* hexadecimal encoding */
1204 int a, b;
1205
1206 if ((a = unhexchar(f[1])) < 0 ||
1207 (b = unhexchar(f[2])) < 0) {
1208 /* Invalid escape code, let's take it literal then */
1209 *(t++) = '\\';
1210 *(t++) = 'x';
1211 } else {
1212 *(t++) = (char) ((a << 4) | b);
1213 f += 2;
1214 }
1215
1216 break;
1217 }
1218
1219 case '0':
1220 case '1':
1221 case '2':
1222 case '3':
1223 case '4':
1224 case '5':
1225 case '6':
1226 case '7': {
1227 /* octal encoding */
1228 int a, b, c;
1229
1230 if ((a = unoctchar(f[0])) < 0 ||
1231 (b = unoctchar(f[1])) < 0 ||
1232 (c = unoctchar(f[2])) < 0) {
1233 /* Invalid escape code, let's take it literal then */
1234 *(t++) = '\\';
1235 *(t++) = f[0];
1236 } else {
1237 *(t++) = (char) ((a << 6) | (b << 3) | c);
1238 f += 2;
1239 }
1240
1241 break;
1242 }
1243
1244 case 0:
1245 /* premature end of string.*/
1246 *(t++) = '\\';
1247 goto finish;
1248
1249 default:
1250 /* Invalid escape code, let's take it literal then */
1251 *(t++) = '\\';
f3d4cc01 1252 *(t++) = *f;
4fe88d28
LP
1253 break;
1254 }
1255 }
1256
1257finish:
1258 *t = 0;
1259 return r;
1260}
1261
6febfd0d
LP
1262char *cunescape(const char *s) {
1263 return cunescape_length(s, strlen(s));
1264}
4fe88d28
LP
1265
1266char *xescape(const char *s, const char *bad) {
1267 char *r, *t;
1268 const char *f;
1269
1270 /* Escapes all chars in bad, in addition to \ and all special
1271 * chars, in \xFF style escaping. May be reversed with
1272 * cunescape. */
1273
1274 if (!(r = new(char, strlen(s)*4+1)))
1275 return NULL;
1276
1277 for (f = s, t = r; *f; f++) {
1278
b866264a
LP
1279 if ((*f < ' ') || (*f >= 127) ||
1280 (*f == '\\') || strchr(bad, *f)) {
4fe88d28
LP
1281 *(t++) = '\\';
1282 *(t++) = 'x';
1283 *(t++) = hexchar(*f >> 4);
1284 *(t++) = hexchar(*f);
1285 } else
1286 *(t++) = *f;
1287 }
1288
1289 *t = 0;
1290
1291 return r;
1292}
1293
ea430986 1294char *bus_path_escape(const char *s) {
ea430986
LP
1295 char *r, *t;
1296 const char *f;
1297
47be870b
LP
1298 assert(s);
1299
ea430986
LP
1300 /* Escapes all chars that D-Bus' object path cannot deal
1301 * with. Can be reverse with bus_path_unescape() */
1302
1303 if (!(r = new(char, strlen(s)*3+1)))
1304 return NULL;
1305
1306 for (f = s, t = r; *f; f++) {
1307
1308 if (!(*f >= 'A' && *f <= 'Z') &&
1309 !(*f >= 'a' && *f <= 'z') &&
1310 !(*f >= '0' && *f <= '9')) {
1311 *(t++) = '_';
1312 *(t++) = hexchar(*f >> 4);
1313 *(t++) = hexchar(*f);
1314 } else
1315 *(t++) = *f;
1316 }
1317
1318 *t = 0;
1319
1320 return r;
1321}
1322
9e2f7c11 1323char *bus_path_unescape(const char *f) {
ea430986 1324 char *r, *t;
ea430986 1325
9e2f7c11 1326 assert(f);
47be870b 1327
9e2f7c11 1328 if (!(r = strdup(f)))
ea430986
LP
1329 return NULL;
1330
9e2f7c11 1331 for (t = r; *f; f++) {
ea430986
LP
1332
1333 if (*f == '_') {
1334 int a, b;
1335
1336 if ((a = unhexchar(f[1])) < 0 ||
1337 (b = unhexchar(f[2])) < 0) {
1338 /* Invalid escape code, let's take it literal then */
1339 *(t++) = '_';
1340 } else {
1341 *(t++) = (char) ((a << 4) | b);
1342 f += 2;
1343 }
1344 } else
1345 *(t++) = *f;
1346 }
1347
1348 *t = 0;
1349
1350 return r;
1351}
1352
4fe88d28
LP
1353char *path_kill_slashes(char *path) {
1354 char *f, *t;
1355 bool slash = false;
1356
1357 /* Removes redundant inner and trailing slashes. Modifies the
1358 * passed string in-place.
1359 *
1360 * ///foo///bar/ becomes /foo/bar
1361 */
1362
1363 for (f = path, t = path; *f; f++) {
1364
1365 if (*f == '/') {
1366 slash = true;
1367 continue;
1368 }
1369
1370 if (slash) {
1371 slash = false;
1372 *(t++) = '/';
1373 }
1374
1375 *(t++) = *f;
1376 }
1377
1378 /* Special rule, if we are talking of the root directory, a
1379 trailing slash is good */
1380
1381 if (t == path && slash)
1382 *(t++) = '/';
1383
1384 *t = 0;
1385 return path;
1386}
1387
1388bool path_startswith(const char *path, const char *prefix) {
1389 assert(path);
1390 assert(prefix);
1391
1392 if ((path[0] == '/') != (prefix[0] == '/'))
1393 return false;
1394
1395 for (;;) {
1396 size_t a, b;
1397
1398 path += strspn(path, "/");
1399 prefix += strspn(prefix, "/");
1400
1401 if (*prefix == 0)
1402 return true;
1403
1404 if (*path == 0)
1405 return false;
1406
1407 a = strcspn(path, "/");
1408 b = strcspn(prefix, "/");
1409
1410 if (a != b)
1411 return false;
1412
1413 if (memcmp(path, prefix, a) != 0)
1414 return false;
1415
1416 path += a;
1417 prefix += b;
1418 }
1419}
1420
15ae422b
LP
1421bool path_equal(const char *a, const char *b) {
1422 assert(a);
1423 assert(b);
1424
1425 if ((a[0] == '/') != (b[0] == '/'))
1426 return false;
1427
1428 for (;;) {
1429 size_t j, k;
1430
1431 a += strspn(a, "/");
1432 b += strspn(b, "/");
1433
1434 if (*a == 0 && *b == 0)
1435 return true;
1436
1437 if (*a == 0 || *b == 0)
1438 return false;
1439
1440 j = strcspn(a, "/");
1441 k = strcspn(b, "/");
1442
1443 if (j != k)
1444 return false;
1445
1446 if (memcmp(a, b, j) != 0)
1447 return false;
1448
1449 a += j;
1450 b += k;
1451 }
1452}
1453
67d51650 1454char *ascii_strlower(char *t) {
4fe88d28
LP
1455 char *p;
1456
67d51650 1457 assert(t);
4fe88d28 1458
67d51650 1459 for (p = t; *p; p++)
4fe88d28
LP
1460 if (*p >= 'A' && *p <= 'Z')
1461 *p = *p - 'A' + 'a';
1462
67d51650 1463 return t;
4fe88d28 1464}
1dccbe19 1465
c85dc17b
LP
1466bool ignore_file(const char *filename) {
1467 assert(filename);
1468
1469 return
1470 filename[0] == '.' ||
6c78be3c 1471 streq(filename, "lost+found") ||
c85dc17b
LP
1472 endswith(filename, "~") ||
1473 endswith(filename, ".rpmnew") ||
1474 endswith(filename, ".rpmsave") ||
1475 endswith(filename, ".rpmorig") ||
1476 endswith(filename, ".dpkg-old") ||
1477 endswith(filename, ".dpkg-new") ||
1478 endswith(filename, ".swp");
1479}
1480
3a0ecb08
LP
1481int fd_nonblock(int fd, bool nonblock) {
1482 int flags;
1483
1484 assert(fd >= 0);
1485
1486 if ((flags = fcntl(fd, F_GETFL, 0)) < 0)
1487 return -errno;
1488
1489 if (nonblock)
1490 flags |= O_NONBLOCK;
1491 else
1492 flags &= ~O_NONBLOCK;
1493
1494 if (fcntl(fd, F_SETFL, flags) < 0)
1495 return -errno;
1496
1497 return 0;
1498}
1499
1500int fd_cloexec(int fd, bool cloexec) {
1501 int flags;
1502
1503 assert(fd >= 0);
1504
1505 if ((flags = fcntl(fd, F_GETFD, 0)) < 0)
1506 return -errno;
1507
1508 if (cloexec)
1509 flags |= FD_CLOEXEC;
1510 else
1511 flags &= ~FD_CLOEXEC;
1512
1513 if (fcntl(fd, F_SETFD, flags) < 0)
1514 return -errno;
1515
1516 return 0;
1517}
1518
a0d40ac5
LP
1519int close_all_fds(const int except[], unsigned n_except) {
1520 DIR *d;
1521 struct dirent *de;
1522 int r = 0;
1523
1524 if (!(d = opendir("/proc/self/fd")))
1525 return -errno;
1526
1527 while ((de = readdir(d))) {
a7610064 1528 int fd = -1;
a0d40ac5 1529
a16e1123 1530 if (ignore_file(de->d_name))
a0d40ac5
LP
1531 continue;
1532
1533 if ((r = safe_atoi(de->d_name, &fd)) < 0)
1534 goto finish;
1535
1536 if (fd < 3)
1537 continue;
1538
1539 if (fd == dirfd(d))
1540 continue;
1541
1542 if (except) {
1543 bool found;
1544 unsigned i;
1545
1546 found = false;
1547 for (i = 0; i < n_except; i++)
1548 if (except[i] == fd) {
1549 found = true;
1550 break;
1551 }
1552
1553 if (found)
1554 continue;
1555 }
1556
2f357920
LP
1557 if ((r = close_nointr(fd)) < 0) {
1558 /* Valgrind has its own FD and doesn't want to have it closed */
1559 if (errno != EBADF)
1560 goto finish;
1561 }
a0d40ac5
LP
1562 }
1563
2f357920
LP
1564 r = 0;
1565
a0d40ac5
LP
1566finish:
1567 closedir(d);
1568 return r;
1569}
1570
db12775d
LP
1571bool chars_intersect(const char *a, const char *b) {
1572 const char *p;
1573
1574 /* Returns true if any of the chars in a are in b. */
1575 for (p = a; *p; p++)
1576 if (strchr(b, *p))
1577 return true;
1578
1579 return false;
1580}
1581
8b6c7120
LP
1582char *format_timestamp(char *buf, size_t l, usec_t t) {
1583 struct tm tm;
1584 time_t sec;
1585
1586 assert(buf);
1587 assert(l > 0);
1588
1589 if (t <= 0)
1590 return NULL;
1591
f872ec33 1592 sec = (time_t) (t / USEC_PER_SEC);
8b6c7120
LP
1593
1594 if (strftime(buf, l, "%a, %d %b %Y %H:%M:%S %z", localtime_r(&sec, &tm)) <= 0)
1595 return NULL;
1596
1597 return buf;
1598}
1599
871d7de4
LP
1600char *format_timespan(char *buf, size_t l, usec_t t) {
1601 static const struct {
1602 const char *suffix;
1603 usec_t usec;
1604 } table[] = {
1605 { "w", USEC_PER_WEEK },
1606 { "d", USEC_PER_DAY },
1607 { "h", USEC_PER_HOUR },
1608 { "min", USEC_PER_MINUTE },
1609 { "s", USEC_PER_SEC },
1610 { "ms", USEC_PER_MSEC },
1611 { "us", 1 },
1612 };
1613
1614 unsigned i;
1615 char *p = buf;
1616
1617 assert(buf);
1618 assert(l > 0);
1619
1620 if (t == (usec_t) -1)
1621 return NULL;
1622
1623 /* The result of this function can be parsed with parse_usec */
1624
1625 for (i = 0; i < ELEMENTSOF(table); i++) {
1626 int k;
1627 size_t n;
1628
1629 if (t < table[i].usec)
1630 continue;
1631
1632 if (l <= 1)
1633 break;
1634
1635 k = snprintf(p, l, "%s%llu%s", p > buf ? " " : "", (unsigned long long) (t / table[i].usec), table[i].suffix);
1636 n = MIN((size_t) k, l);
1637
1638 l -= n;
1639 p += n;
1640
1641 t %= table[i].usec;
1642 }
1643
1644 *p = 0;
1645
1646 return buf;
1647}
1648
42856c10
LP
1649bool fstype_is_network(const char *fstype) {
1650 static const char * const table[] = {
1651 "cifs",
1652 "smbfs",
1653 "ncpfs",
1654 "nfs",
ca139f94
LP
1655 "nfs4",
1656 "gfs",
1657 "gfs2"
42856c10
LP
1658 };
1659
1660 unsigned i;
1661
1662 for (i = 0; i < ELEMENTSOF(table); i++)
1663 if (streq(table[i], fstype))
1664 return true;
1665
1666 return false;
1667}
1668
601f6a1e
LP
1669int chvt(int vt) {
1670 int fd, r = 0;
1671
1672 if ((fd = open("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0)
1673 return -errno;
1674
1675 if (vt < 0) {
1676 int tiocl[2] = {
1677 TIOCL_GETKMSGREDIRECT,
1678 0
1679 };
1680
1681 if (ioctl(fd, TIOCLINUX, tiocl) < 0)
1682 return -errno;
1683
1684 vt = tiocl[0] <= 0 ? 1 : tiocl[0];
1685 }
1686
1687 if (ioctl(fd, VT_ACTIVATE, vt) < 0)
1688 r = -errno;
1689
a16e1123 1690 close_nointr_nofail(r);
601f6a1e
LP
1691 return r;
1692}
1693
80876c20
LP
1694int read_one_char(FILE *f, char *ret, bool *need_nl) {
1695 struct termios old_termios, new_termios;
1696 char c;
1697 char line[1024];
1698
1699 assert(f);
1700 assert(ret);
1701
1702 if (tcgetattr(fileno(f), &old_termios) >= 0) {
1703 new_termios = old_termios;
1704
1705 new_termios.c_lflag &= ~ICANON;
1706 new_termios.c_cc[VMIN] = 1;
1707 new_termios.c_cc[VTIME] = 0;
1708
1709 if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) {
1710 size_t k;
1711
1712 k = fread(&c, 1, 1, f);
1713
1714 tcsetattr(fileno(f), TCSADRAIN, &old_termios);
1715
1716 if (k <= 0)
1717 return -EIO;
1718
1719 if (need_nl)
1720 *need_nl = c != '\n';
1721
1722 *ret = c;
1723 return 0;
1724 }
1725 }
1726
1727 if (!(fgets(line, sizeof(line), f)))
1728 return -EIO;
1729
1730 truncate_nl(line);
1731
1732 if (strlen(line) != 1)
1733 return -EBADMSG;
1734
1735 if (need_nl)
1736 *need_nl = false;
1737
1738 *ret = line[0];
1739 return 0;
1740}
1741
1742int ask(char *ret, const char *replies, const char *text, ...) {
1743 assert(ret);
1744 assert(replies);
1745 assert(text);
1746
1747 for (;;) {
1748 va_list ap;
1749 char c;
1750 int r;
1751 bool need_nl = true;
1752
b1b2dc0c
LP
1753 fputs("\x1B[1m", stdout);
1754
80876c20
LP
1755 va_start(ap, text);
1756 vprintf(text, ap);
1757 va_end(ap);
1758
b1b2dc0c
LP
1759 fputs("\x1B[0m", stdout);
1760
80876c20
LP
1761 fflush(stdout);
1762
1763 if ((r = read_one_char(stdin, &c, &need_nl)) < 0) {
1764
1765 if (r == -EBADMSG) {
1766 puts("Bad input, please try again.");
1767 continue;
1768 }
1769
1770 putchar('\n');
1771 return r;
1772 }
1773
1774 if (need_nl)
1775 putchar('\n');
1776
1777 if (strchr(replies, c)) {
1778 *ret = c;
1779 return 0;
1780 }
1781
1782 puts("Read unexpected character, please try again.");
1783 }
1784}
1785
1786int reset_terminal(int fd) {
1787 struct termios termios;
1788 int r = 0;
1789
1790 assert(fd >= 0);
1791
aaf694ca 1792 /* Set terminal to some sane defaults */
80876c20
LP
1793
1794 if (tcgetattr(fd, &termios) < 0) {
1795 r = -errno;
1796 goto finish;
1797 }
1798
aaf694ca
LP
1799 /* We only reset the stuff that matters to the software. How
1800 * hardware is set up we don't touch assuming that somebody
1801 * else will do that for us */
1802
1803 termios.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | IUCLC);
80876c20
LP
1804 termios.c_iflag |= ICRNL | IMAXBEL | IUTF8;
1805 termios.c_oflag |= ONLCR;
1806 termios.c_cflag |= CREAD;
1807 termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOPRT | ECHOKE;
1808
1809 termios.c_cc[VINTR] = 03; /* ^C */
1810 termios.c_cc[VQUIT] = 034; /* ^\ */
1811 termios.c_cc[VERASE] = 0177;
1812 termios.c_cc[VKILL] = 025; /* ^X */
1813 termios.c_cc[VEOF] = 04; /* ^D */
1814 termios.c_cc[VSTART] = 021; /* ^Q */
1815 termios.c_cc[VSTOP] = 023; /* ^S */
1816 termios.c_cc[VSUSP] = 032; /* ^Z */
1817 termios.c_cc[VLNEXT] = 026; /* ^V */
1818 termios.c_cc[VWERASE] = 027; /* ^W */
1819 termios.c_cc[VREPRINT] = 022; /* ^R */
aaf694ca
LP
1820 termios.c_cc[VEOL] = 0;
1821 termios.c_cc[VEOL2] = 0;
80876c20
LP
1822
1823 termios.c_cc[VTIME] = 0;
1824 termios.c_cc[VMIN] = 1;
1825
1826 if (tcsetattr(fd, TCSANOW, &termios) < 0)
1827 r = -errno;
1828
1829finish:
1830 /* Just in case, flush all crap out */
1831 tcflush(fd, TCIOFLUSH);
1832
1833 return r;
1834}
1835
1836int open_terminal(const char *name, int mode) {
1837 int fd, r;
1838
1839 if ((fd = open(name, mode)) < 0)
1840 return -errno;
1841
1842 if ((r = isatty(fd)) < 0) {
1843 close_nointr_nofail(fd);
1844 return -errno;
1845 }
1846
1847 if (!r) {
1848 close_nointr_nofail(fd);
1849 return -ENOTTY;
1850 }
1851
1852 return fd;
1853}
1854
1855int flush_fd(int fd) {
1856 struct pollfd pollfd;
1857
1858 zero(pollfd);
1859 pollfd.fd = fd;
1860 pollfd.events = POLLIN;
1861
1862 for (;;) {
1863 char buf[1024];
1864 ssize_t l;
1865 int r;
1866
1867 if ((r = poll(&pollfd, 1, 0)) < 0) {
1868
1869 if (errno == EINTR)
1870 continue;
1871
1872 return -errno;
1873 }
1874
1875 if (r == 0)
1876 return 0;
1877
1878 if ((l = read(fd, buf, sizeof(buf))) < 0) {
1879
1880 if (errno == EINTR)
1881 continue;
1882
1883 if (errno == EAGAIN)
1884 return 0;
1885
1886 return -errno;
1887 }
1888
1889 if (l <= 0)
1890 return 0;
1891 }
1892}
1893
21de3988 1894int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocstty_eperm) {
bab45044 1895 int fd = -1, notify = -1, r, wd = -1;
80876c20
LP
1896
1897 assert(name);
1898
1899 /* We use inotify to be notified when the tty is closed. We
1900 * create the watch before checking if we can actually acquire
1901 * it, so that we don't lose any event.
1902 *
1903 * Note: strictly speaking this actually watches for the
1904 * device being closed, it does *not* really watch whether a
1905 * tty loses its controlling process. However, unless some
1906 * rogue process uses TIOCNOTTY on /dev/tty *after* closing
1907 * its tty otherwise this will not become a problem. As long
1908 * as the administrator makes sure not configure any service
1909 * on the same tty as an untrusted user this should not be a
1910 * problem. (Which he probably should not do anyway.) */
1911
1912 if (!fail && !force) {
1913 if ((notify = inotify_init1(IN_CLOEXEC)) < 0) {
1914 r = -errno;
1915 goto fail;
1916 }
1917
1918 if ((wd = inotify_add_watch(notify, name, IN_CLOSE)) < 0) {
1919 r = -errno;
1920 goto fail;
1921 }
1922 }
1923
1924 for (;;) {
e3d1855b
LP
1925 if (notify >= 0)
1926 if ((r = flush_fd(notify)) < 0)
1927 goto fail;
80876c20
LP
1928
1929 /* We pass here O_NOCTTY only so that we can check the return
1930 * value TIOCSCTTY and have a reliable way to figure out if we
1931 * successfully became the controlling process of the tty */
1932 if ((fd = open_terminal(name, O_RDWR|O_NOCTTY)) < 0)
1933 return -errno;
1934
1935 /* First, try to get the tty */
21de3988
LP
1936 r = ioctl(fd, TIOCSCTTY, force);
1937
1938 /* Sometimes it makes sense to ignore TIOCSCTTY
1939 * returning EPERM, i.e. when very likely we already
1940 * are have this controlling terminal. */
1941 if (r < 0 && errno == EPERM && ignore_tiocstty_eperm)
1942 r = 0;
1943
1944 if (r < 0 && (force || fail || errno != EPERM)) {
80876c20
LP
1945 r = -errno;
1946 goto fail;
1947 }
1948
1949 if (r >= 0)
1950 break;
1951
1952 assert(!fail);
1953 assert(!force);
1954 assert(notify >= 0);
1955
1956 for (;;) {
1957 struct inotify_event e;
1958 ssize_t l;
1959
1960 if ((l = read(notify, &e, sizeof(e))) != sizeof(e)) {
1961
1962 if (l < 0) {
1963
1964 if (errno == EINTR)
1965 continue;
1966
1967 r = -errno;
1968 } else
1969 r = -EIO;
1970
1971 goto fail;
1972 }
1973
1974 if (e.wd != wd || !(e.mask & IN_CLOSE)) {
1975 r = -errno;
1976 goto fail;
1977 }
1978
1979 break;
1980 }
1981
1982 /* We close the tty fd here since if the old session
1983 * ended our handle will be dead. It's important that
1984 * we do this after sleeping, so that we don't enter
1985 * an endless loop. */
1986 close_nointr_nofail(fd);
1987 }
1988
1989 if (notify >= 0)
a16e1123 1990 close_nointr_nofail(notify);
80876c20
LP
1991
1992 if ((r = reset_terminal(fd)) < 0)
1993 log_warning("Failed to reset terminal: %s", strerror(-r));
1994
1995 return fd;
1996
1997fail:
1998 if (fd >= 0)
a16e1123 1999 close_nointr_nofail(fd);
80876c20
LP
2000
2001 if (notify >= 0)
a16e1123 2002 close_nointr_nofail(notify);
80876c20
LP
2003
2004 return r;
2005}
2006
2007int release_terminal(void) {
2008 int r = 0, fd;
57cd2192 2009 struct sigaction sa_old, sa_new;
80876c20 2010
57cd2192 2011 if ((fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY)) < 0)
80876c20
LP
2012 return -errno;
2013
57cd2192
LP
2014 /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
2015 * by our own TIOCNOTTY */
2016
2017 zero(sa_new);
2018 sa_new.sa_handler = SIG_IGN;
2019 sa_new.sa_flags = SA_RESTART;
2020 assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
2021
80876c20
LP
2022 if (ioctl(fd, TIOCNOTTY) < 0)
2023 r = -errno;
2024
57cd2192
LP
2025 assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
2026
80876c20
LP
2027 close_nointr_nofail(fd);
2028 return r;
2029}
2030
9a34ec5f
LP
2031int sigaction_many(const struct sigaction *sa, ...) {
2032 va_list ap;
2033 int r = 0, sig;
2034
2035 va_start(ap, sa);
2036 while ((sig = va_arg(ap, int)) > 0)
2037 if (sigaction(sig, sa, NULL) < 0)
2038 r = -errno;
2039 va_end(ap);
2040
2041 return r;
2042}
2043
2044int ignore_signals(int sig, ...) {
a337c6fc 2045 struct sigaction sa;
9a34ec5f
LP
2046 va_list ap;
2047 int r = 0;
a337c6fc
LP
2048
2049 zero(sa);
2050 sa.sa_handler = SIG_IGN;
2051 sa.sa_flags = SA_RESTART;
2052
9a34ec5f
LP
2053 if (sigaction(sig, &sa, NULL) < 0)
2054 r = -errno;
2055
2056 va_start(ap, sig);
2057 while ((sig = va_arg(ap, int)) > 0)
2058 if (sigaction(sig, &sa, NULL) < 0)
2059 r = -errno;
2060 va_end(ap);
2061
2062 return r;
2063}
2064
2065int default_signals(int sig, ...) {
2066 struct sigaction sa;
2067 va_list ap;
2068 int r = 0;
2069
2070 zero(sa);
2071 sa.sa_handler = SIG_DFL;
2072 sa.sa_flags = SA_RESTART;
2073
2074 if (sigaction(sig, &sa, NULL) < 0)
2075 r = -errno;
2076
2077 va_start(ap, sig);
2078 while ((sig = va_arg(ap, int)) > 0)
2079 if (sigaction(sig, &sa, NULL) < 0)
2080 r = -errno;
2081 va_end(ap);
2082
2083 return r;
a337c6fc
LP
2084}
2085
8d567588
LP
2086int close_pipe(int p[]) {
2087 int a = 0, b = 0;
2088
2089 assert(p);
2090
2091 if (p[0] >= 0) {
2092 a = close_nointr(p[0]);
2093 p[0] = -1;
2094 }
2095
2096 if (p[1] >= 0) {
2097 b = close_nointr(p[1]);
2098 p[1] = -1;
2099 }
2100
2101 return a < 0 ? a : b;
2102}
2103
eb22ac37 2104ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
8d567588
LP
2105 uint8_t *p;
2106 ssize_t n = 0;
2107
2108 assert(fd >= 0);
2109 assert(buf);
2110
2111 p = buf;
2112
2113 while (nbytes > 0) {
2114 ssize_t k;
2115
2116 if ((k = read(fd, p, nbytes)) <= 0) {
2117
eb22ac37 2118 if (k < 0 && errno == EINTR)
8d567588
LP
2119 continue;
2120
eb22ac37 2121 if (k < 0 && errno == EAGAIN && do_poll) {
8d567588
LP
2122 struct pollfd pollfd;
2123
2124 zero(pollfd);
2125 pollfd.fd = fd;
2126 pollfd.events = POLLIN;
2127
2128 if (poll(&pollfd, 1, -1) < 0) {
2129 if (errno == EINTR)
2130 continue;
2131
2132 return n > 0 ? n : -errno;
2133 }
2134
2135 if (pollfd.revents != POLLIN)
2136 return n > 0 ? n : -EIO;
2137
2138 continue;
2139 }
2140
2141 return n > 0 ? n : (k < 0 ? -errno : 0);
2142 }
2143
2144 p += k;
2145 nbytes -= k;
2146 n += k;
2147 }
2148
2149 return n;
2150}
2151
eb22ac37
LP
2152ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
2153 const uint8_t *p;
2154 ssize_t n = 0;
2155
2156 assert(fd >= 0);
2157 assert(buf);
2158
2159 p = buf;
2160
2161 while (nbytes > 0) {
2162 ssize_t k;
2163
2164 if ((k = write(fd, p, nbytes)) <= 0) {
2165
2166 if (k < 0 && errno == EINTR)
2167 continue;
2168
2169 if (k < 0 && errno == EAGAIN && do_poll) {
2170 struct pollfd pollfd;
2171
2172 zero(pollfd);
2173 pollfd.fd = fd;
2174 pollfd.events = POLLOUT;
2175
2176 if (poll(&pollfd, 1, -1) < 0) {
2177 if (errno == EINTR)
2178 continue;
2179
2180 return n > 0 ? n : -errno;
2181 }
2182
2183 if (pollfd.revents != POLLOUT)
2184 return n > 0 ? n : -EIO;
2185
2186 continue;
2187 }
2188
2189 return n > 0 ? n : (k < 0 ? -errno : 0);
2190 }
2191
2192 p += k;
2193 nbytes -= k;
2194 n += k;
2195 }
2196
2197 return n;
2198}
2199
8d567588
LP
2200int path_is_mount_point(const char *t) {
2201 struct stat a, b;
2202 char *copy;
2203
2204 if (lstat(t, &a) < 0) {
2205
2206 if (errno == ENOENT)
2207 return 0;
2208
2209 return -errno;
2210 }
2211
2212 if (!(copy = strdup(t)))
2213 return -ENOMEM;
2214
2215 if (lstat(dirname(copy), &b) < 0) {
2216 free(copy);
2217 return -errno;
2218 }
2219
2220 free(copy);
2221
2222 return a.st_dev != b.st_dev;
2223}
2224
24a6e4a4
LP
2225int parse_usec(const char *t, usec_t *usec) {
2226 static const struct {
2227 const char *suffix;
2228 usec_t usec;
2229 } table[] = {
2230 { "sec", USEC_PER_SEC },
2231 { "s", USEC_PER_SEC },
2232 { "min", USEC_PER_MINUTE },
2233 { "hr", USEC_PER_HOUR },
2234 { "h", USEC_PER_HOUR },
2235 { "d", USEC_PER_DAY },
2236 { "w", USEC_PER_WEEK },
2237 { "msec", USEC_PER_MSEC },
2238 { "ms", USEC_PER_MSEC },
2239 { "m", USEC_PER_MINUTE },
2240 { "usec", 1ULL },
2241 { "us", 1ULL },
2242 { "", USEC_PER_SEC },
2243 };
2244
2245 const char *p;
2246 usec_t r = 0;
2247
2248 assert(t);
2249 assert(usec);
2250
2251 p = t;
2252 do {
2253 long long l;
2254 char *e;
2255 unsigned i;
2256
2257 errno = 0;
2258 l = strtoll(p, &e, 10);
2259
2260 if (errno != 0)
2261 return -errno;
2262
2263 if (l < 0)
2264 return -ERANGE;
2265
2266 if (e == p)
2267 return -EINVAL;
2268
2269 e += strspn(e, WHITESPACE);
2270
2271 for (i = 0; i < ELEMENTSOF(table); i++)
2272 if (startswith(e, table[i].suffix)) {
2273 r += (usec_t) l * table[i].usec;
2274 p = e + strlen(table[i].suffix);
2275 break;
2276 }
2277
2278 if (i >= ELEMENTSOF(table))
2279 return -EINVAL;
2280
2281 } while (*p != 0);
2282
2283 *usec = r;
2284
2285 return 0;
2286}
2287
843d2643
LP
2288int make_stdio(int fd) {
2289 int r, s, t;
2290
2291 assert(fd >= 0);
2292
2293 r = dup2(fd, STDIN_FILENO);
2294 s = dup2(fd, STDOUT_FILENO);
2295 t = dup2(fd, STDERR_FILENO);
2296
2297 if (fd >= 3)
2298 close_nointr_nofail(fd);
2299
2300 if (r < 0 || s < 0 || t < 0)
2301 return -errno;
2302
2303 return 0;
2304}
2305
cb8a8f78
LP
2306bool is_clean_exit(int code, int status) {
2307
2308 if (code == CLD_EXITED)
2309 return status == 0;
2310
2311 /* If a daemon does not implement handlers for some of the
2312 * signals that's not considered an unclean shutdown */
2313 if (code == CLD_KILLED)
2314 return
2315 status == SIGHUP ||
2316 status == SIGINT ||
2317 status == SIGTERM ||
2318 status == SIGPIPE;
2319
2320 return false;
2321}
2322
8407a5d0
LP
2323bool is_device_path(const char *path) {
2324
2325 /* Returns true on paths that refer to a device, either in
2326 * sysfs or in /dev */
2327
2328 return
2329 path_startswith(path, "/dev/") ||
2330 path_startswith(path, "/sys/");
2331}
2332
01f78473
LP
2333int dir_is_empty(const char *path) {
2334 DIR *d;
2335 int r;
2336 struct dirent buf, *de;
2337
2338 if (!(d = opendir(path)))
2339 return -errno;
2340
2341 for (;;) {
2342 if ((r = readdir_r(d, &buf, &de)) > 0) {
2343 r = -r;
2344 break;
2345 }
2346
2347 if (!de) {
2348 r = 1;
2349 break;
2350 }
2351
2352 if (!ignore_file(de->d_name)) {
2353 r = 0;
2354 break;
2355 }
2356 }
2357
2358 closedir(d);
2359 return r;
2360}
2361
d3782d60
LP
2362unsigned long long random_ull(void) {
2363 int fd;
2364 uint64_t ull;
2365 ssize_t r;
2366
2367 if ((fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY)) < 0)
2368 goto fallback;
2369
eb22ac37 2370 r = loop_read(fd, &ull, sizeof(ull), true);
d3782d60
LP
2371 close_nointr_nofail(fd);
2372
2373 if (r != sizeof(ull))
2374 goto fallback;
2375
2376 return ull;
2377
2378fallback:
2379 return random() * RAND_MAX + random();
2380}
2381
5b6319dc
LP
2382void rename_process(const char name[8]) {
2383 assert(name);
2384
2385 prctl(PR_SET_NAME, name);
2386
2387 /* This is a like a poor man's setproctitle(). The string
2388 * passed should fit in 7 chars (i.e. the length of
2389 * "systemd") */
2390
2391 if (program_invocation_name)
2392 strncpy(program_invocation_name, name, strlen(program_invocation_name));
2393}
2394
7d793605
LP
2395void sigset_add_many(sigset_t *ss, ...) {
2396 va_list ap;
2397 int sig;
2398
2399 assert(ss);
2400
2401 va_start(ap, ss);
2402 while ((sig = va_arg(ap, int)) > 0)
2403 assert_se(sigaddset(ss, sig) == 0);
2404 va_end(ap);
2405}
2406
ef2f1067
LP
2407char* gethostname_malloc(void) {
2408 struct utsname u;
2409
2410 assert_se(uname(&u) >= 0);
2411
2412 if (u.nodename[0])
2413 return strdup(u.nodename);
2414
2415 return strdup(u.sysname);
2416}
2417
8c6db833
LP
2418int getmachineid_malloc(char **b) {
2419 int r;
2420
2421 assert(b);
2422
2423 if ((r = read_one_line_file("/var/lib/dbus/machine-id", b)) < 0)
2424 return r;
2425
2426 strstrip(*b);
2427 return 0;
2428}
2429
ef2f1067
LP
2430char* getlogname_malloc(void) {
2431 uid_t uid;
2432 long bufsize;
2433 char *buf, *name;
2434 struct passwd pwbuf, *pw = NULL;
2435 struct stat st;
2436
2437 if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0)
2438 uid = st.st_uid;
2439 else
2440 uid = getuid();
2441
2442 /* Shortcut things to avoid NSS lookups */
2443 if (uid == 0)
2444 return strdup("root");
2445
2446 if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) <= 0)
2447 bufsize = 4096;
2448
2449 if (!(buf = malloc(bufsize)))
2450 return NULL;
2451
2452 if (getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0 && pw) {
2453 name = strdup(pw->pw_name);
2454 free(buf);
2455 return name;
2456 }
2457
2458 free(buf);
2459
2460 if (asprintf(&name, "%lu", (unsigned long) uid) < 0)
2461 return NULL;
2462
2463 return name;
2464}
2465
8c6db833
LP
2466int getttyname_malloc(char **r) {
2467 char path[PATH_MAX], *p, *c;
2468
2469 assert(r);
ef2f1067
LP
2470
2471 if (ttyname_r(STDIN_FILENO, path, sizeof(path)) < 0)
8c6db833 2472 return -errno;
ef2f1067
LP
2473
2474 char_array_0(path);
2475
2476 p = path;
2477 if (startswith(path, "/dev/"))
2478 p += 5;
2479
8c6db833
LP
2480 if (!(c = strdup(p)))
2481 return -ENOMEM;
2482
2483 *r = c;
2484 return 0;
2485}
2486
2487static int rm_rf_children(int fd, bool only_dirs) {
2488 DIR *d;
2489 int ret = 0;
2490
2491 assert(fd >= 0);
2492
2493 /* This returns the first error we run into, but nevertheless
2494 * tries to go on */
2495
2496 if (!(d = fdopendir(fd))) {
2497 close_nointr_nofail(fd);
2498 return -errno;
2499 }
2500
2501 for (;;) {
2502 struct dirent buf, *de;
2503 bool is_dir;
2504 int r;
2505
2506 if ((r = readdir_r(d, &buf, &de)) != 0) {
2507 if (ret == 0)
2508 ret = -r;
2509 break;
2510 }
2511
2512 if (!de)
2513 break;
2514
2515 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
2516 continue;
2517
2518 if (de->d_type == DT_UNKNOWN) {
2519 struct stat st;
2520
2521 if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2522 if (ret == 0)
2523 ret = -errno;
2524 continue;
2525 }
2526
2527 is_dir = S_ISDIR(st.st_mode);
2528 } else
2529 is_dir = de->d_type == DT_DIR;
2530
2531 if (is_dir) {
2532 int subdir_fd;
2533
2534 if ((subdir_fd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)) < 0) {
2535 if (ret == 0)
2536 ret = -errno;
2537 continue;
2538 }
2539
2540 if ((r = rm_rf_children(subdir_fd, only_dirs)) < 0) {
2541 if (ret == 0)
2542 ret = r;
2543 }
2544
2545 if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
2546 if (ret == 0)
2547 ret = -errno;
2548 }
2549 } else if (!only_dirs) {
2550
2551 if (unlinkat(fd, de->d_name, 0) < 0) {
2552 if (ret == 0)
2553 ret = -errno;
2554 }
2555 }
2556 }
2557
2558 closedir(d);
2559
2560 return ret;
2561}
2562
2563int rm_rf(const char *path, bool only_dirs, bool delete_root) {
2564 int fd;
2565 int r;
2566
2567 assert(path);
2568
2569 if ((fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)) < 0) {
2570
2571 if (errno != ENOTDIR)
2572 return -errno;
2573
2574 if (delete_root && !only_dirs)
2575 if (unlink(path) < 0)
2576 return -errno;
2577
2578 return 0;
2579 }
2580
2581 r = rm_rf_children(fd, only_dirs);
2582
2583 if (delete_root)
2584 if (rmdir(path) < 0) {
2585 if (r == 0)
2586 r = -errno;
2587 }
2588
2589 return r;
2590}
2591
2592int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
2593 assert(path);
2594
2595 /* Under the assumption that we are running privileged we
2596 * first change the access mode and only then hand out
2597 * ownership to avoid a window where access is too open. */
2598
2599 if (chmod(path, mode) < 0)
2600 return -errno;
2601
2602 if (chown(path, uid, gid) < 0)
2603 return -errno;
2604
2605 return 0;
ef2f1067
LP
2606}
2607
82c121a4
LP
2608cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
2609 cpu_set_t *r;
2610 unsigned n = 1024;
2611
2612 /* Allocates the cpuset in the right size */
2613
2614 for (;;) {
2615 if (!(r = CPU_ALLOC(n)))
2616 return NULL;
2617
2618 if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), r) >= 0) {
2619 CPU_ZERO_S(CPU_ALLOC_SIZE(n), r);
2620
2621 if (ncpus)
2622 *ncpus = n;
2623
2624 return r;
2625 }
2626
2627 CPU_FREE(r);
2628
2629 if (errno != EINVAL)
2630 return NULL;
2631
2632 n *= 2;
2633 }
2634}
2635
9e58ff9c
LP
2636void status_vprintf(const char *format, va_list ap) {
2637 char *s = NULL;
2638 int fd = -1;
2639
2640 assert(format);
2641
2642 /* This independent of logging, as status messages are
2643 * optional and go exclusively to the console. */
2644
2645 if (vasprintf(&s, format, ap) < 0)
2646 goto finish;
2647
2648 if ((fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0)
2649 goto finish;
2650
2651 write(fd, s, strlen(s));
2652
2653finish:
2654 free(s);
2655
2656 if (fd >= 0)
2657 close_nointr_nofail(fd);
2658}
2659
c846ff47
LP
2660void status_printf(const char *format, ...) {
2661 va_list ap;
2662
2663 assert(format);
2664
2665 va_start(ap, format);
2666 status_vprintf(format, ap);
2667 va_end(ap);
2668}
2669
2670void status_welcome(void) {
2671
2672#if defined(TARGET_FEDORA)
2673 char *r;
2674
2675 if (read_one_line_file("/etc/system-release", &r) < 0)
2676 return;
2677
2678 truncate_nl(r);
2679
2680 /* This tries to mimic the color magic the old Red Hat sysinit
2681 * script did. */
2682
2683 if (startswith(r, "Red Hat"))
2e54424d 2684 status_printf("Welcome to \x1B[0;31m%s\x1B[0m!\n", r); /* Red for RHEL */
c846ff47 2685 else if (startswith(r, "Fedora"))
2e54424d 2686 status_printf("Welcome to \x1B[0;34m%s\x1B[0m!\n", r); /* Blue for Fedora */
c846ff47 2687 else
2e54424d 2688 status_printf("Welcome to %s!\n", r);
c846ff47
LP
2689
2690 free(r);
2691
2692#elif defined(TARGET_SUSE)
2693 char *r;
2694
2695 if (read_one_line_file("/etc/SuSE-release", &r) < 0)
2696 return;
2697
2698 truncate_nl(r);
2699
2e54424d 2700 status_printf("Welcome to \x1B[0;32m%s\x1B[0m!\n", r); /* Green for SUSE */
c846ff47
LP
2701 free(r);
2702#else
2703#warning "You probably should add a welcome text logic here."
2704#endif
2705}
2706
fab56fc5
LP
2707char *replace_env(const char *format, char **env) {
2708 enum {
2709 WORD,
2710 DOLLAR,
2711 VARIABLE
2712 } state = WORD;
2713
2714 const char *e, *word = format;
2715 char *r = NULL, *k;
2716
2717 assert(format);
2718
2719 for (e = format; *e; e ++) {
2720
2721 switch (state) {
2722
2723 case WORD:
2724 if (*e == '$')
2725 state = DOLLAR;
2726 break;
2727
2728 case DOLLAR:
2729 if (*e == '(') {
2730 if (!(k = strnappend(r, word, e-word-1)))
2731 goto fail;
2732
2733 free(r);
2734 r = k;
2735
2736 word = e-1;
2737 state = VARIABLE;
2738
2739 } else if (*e == '$') {
2740 if (!(k = strnappend(r, word, e-word)))
2741 goto fail;
2742
2743 free(r);
2744 r = k;
2745
2746 word = e+1;
2747 state = WORD;
2748 } else
2749 state = WORD;
2750 break;
2751
2752 case VARIABLE:
2753 if (*e == ')') {
2754 char *t;
2755
2756 if ((t = strv_env_get_with_length(env, word+2, e-word-2))) {
2757 if (!(k = strappend(r, t)))
2758 goto fail;
2759
2760 free(r);
2761 r = k;
2762
2763 word = e+1;
2764 }
2765
2766 state = WORD;
2767 }
2768 break;
2769 }
2770 }
2771
2772 if (!(k = strnappend(r, word, e-word)))
2773 goto fail;
2774
2775 free(r);
2776 return k;
2777
2778fail:
2779 free(r);
2780 return NULL;
2781}
2782
2783char **replace_env_argv(char **argv, char **env) {
2784 char **r, **i;
301056b7 2785 unsigned k = 0;
fab56fc5
LP
2786
2787 if (!(r = new(char*, strv_length(argv)+1)))
2788 return NULL;
2789
2790 STRV_FOREACH(i, argv) {
2791 if (!(r[k++] = replace_env(*i, env))) {
2792 strv_free(r);
2793 return NULL;
2794 }
2795 }
2796
2797 r[k] = NULL;
2798 return r;
2799}
2800
1dccbe19
LP
2801static const char *const ioprio_class_table[] = {
2802 [IOPRIO_CLASS_NONE] = "none",
2803 [IOPRIO_CLASS_RT] = "realtime",
2804 [IOPRIO_CLASS_BE] = "best-effort",
2805 [IOPRIO_CLASS_IDLE] = "idle"
2806};
2807
2808DEFINE_STRING_TABLE_LOOKUP(ioprio_class, int);
2809
2810static const char *const sigchld_code_table[] = {
2811 [CLD_EXITED] = "exited",
2812 [CLD_KILLED] = "killed",
2813 [CLD_DUMPED] = "dumped",
2814 [CLD_TRAPPED] = "trapped",
2815 [CLD_STOPPED] = "stopped",
2816 [CLD_CONTINUED] = "continued",
2817};
2818
2819DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
2820
2821static const char *const log_facility_table[LOG_NFACILITIES] = {
2822 [LOG_FAC(LOG_KERN)] = "kern",
2823 [LOG_FAC(LOG_USER)] = "user",
2824 [LOG_FAC(LOG_MAIL)] = "mail",
2825 [LOG_FAC(LOG_DAEMON)] = "daemon",
2826 [LOG_FAC(LOG_AUTH)] = "auth",
2827 [LOG_FAC(LOG_SYSLOG)] = "syslog",
2828 [LOG_FAC(LOG_LPR)] = "lpr",
2829 [LOG_FAC(LOG_NEWS)] = "news",
2830 [LOG_FAC(LOG_UUCP)] = "uucp",
2831 [LOG_FAC(LOG_CRON)] = "cron",
2832 [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
2833 [LOG_FAC(LOG_FTP)] = "ftp",
2834 [LOG_FAC(LOG_LOCAL0)] = "local0",
2835 [LOG_FAC(LOG_LOCAL1)] = "local1",
2836 [LOG_FAC(LOG_LOCAL2)] = "local2",
2837 [LOG_FAC(LOG_LOCAL3)] = "local3",
2838 [LOG_FAC(LOG_LOCAL4)] = "local4",
2839 [LOG_FAC(LOG_LOCAL5)] = "local5",
2840 [LOG_FAC(LOG_LOCAL6)] = "local6",
2841 [LOG_FAC(LOG_LOCAL7)] = "local7"
2842};
2843
2844DEFINE_STRING_TABLE_LOOKUP(log_facility, int);
2845
2846static const char *const log_level_table[] = {
2847 [LOG_EMERG] = "emerg",
2848 [LOG_ALERT] = "alert",
2849 [LOG_CRIT] = "crit",
2850 [LOG_ERR] = "err",
2851 [LOG_WARNING] = "warning",
2852 [LOG_NOTICE] = "notice",
2853 [LOG_INFO] = "info",
2854 [LOG_DEBUG] = "debug"
2855};
2856
2857DEFINE_STRING_TABLE_LOOKUP(log_level, int);
2858
2859static const char* const sched_policy_table[] = {
2860 [SCHED_OTHER] = "other",
2861 [SCHED_BATCH] = "batch",
2862 [SCHED_IDLE] = "idle",
2863 [SCHED_FIFO] = "fifo",
2864 [SCHED_RR] = "rr"
2865};
2866
2867DEFINE_STRING_TABLE_LOOKUP(sched_policy, int);
2868
2869static const char* const rlimit_table[] = {
2870 [RLIMIT_CPU] = "LimitCPU",
2871 [RLIMIT_FSIZE] = "LimitFSIZE",
2872 [RLIMIT_DATA] = "LimitDATA",
2873 [RLIMIT_STACK] = "LimitSTACK",
2874 [RLIMIT_CORE] = "LimitCORE",
2875 [RLIMIT_RSS] = "LimitRSS",
2876 [RLIMIT_NOFILE] = "LimitNOFILE",
2877 [RLIMIT_AS] = "LimitAS",
2878 [RLIMIT_NPROC] = "LimitNPROC",
2879 [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
2880 [RLIMIT_LOCKS] = "LimitLOCKS",
2881 [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
2882 [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
2883 [RLIMIT_NICE] = "LimitNICE",
2884 [RLIMIT_RTPRIO] = "LimitRTPRIO",
2885 [RLIMIT_RTTIME] = "LimitRTTIME"
2886};
2887
2888DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
4fd5948e
LP
2889
2890static const char* const ip_tos_table[] = {
2891 [IPTOS_LOWDELAY] = "low-delay",
2892 [IPTOS_THROUGHPUT] = "throughput",
2893 [IPTOS_RELIABILITY] = "reliability",
2894 [IPTOS_LOWCOST] = "low-cost",
2895};
2896
2897DEFINE_STRING_TABLE_LOOKUP(ip_tos, int);