]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/util.c
man: explain a couple of default dependencies
[thirdparty/systemd.git] / src / 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
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>
3fe5e5d4 50#include <linux/kd.h>
afea26ad 51#include <dlfcn.h>
2e78aa99 52#include <sys/wait.h>
60918275
LP
53
54#include "macro.h"
55#include "util.h"
1dccbe19
LP
56#include "ioprio.h"
57#include "missing.h"
a9f5d454 58#include "log.h"
65d2ebdc 59#include "strv.h"
e51bc1a2 60#include "label.h"
d06dacd0 61#include "exit-status.h"
83cc030f 62#include "hashmap.h"
56cf987f 63
e05797fb
LP
64bool streq_ptr(const char *a, const char *b) {
65
66 /* Like streq(), but tries to make sense of NULL pointers */
67
68 if (a && b)
69 return streq(a, b);
70
71 if (!a && !b)
72 return true;
73
74 return false;
75}
76
47be870b 77usec_t now(clockid_t clock_id) {
60918275
LP
78 struct timespec ts;
79
47be870b 80 assert_se(clock_gettime(clock_id, &ts) == 0);
60918275
LP
81
82 return timespec_load(&ts);
83}
84
63983207 85dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
871d7de4
LP
86 assert(ts);
87
88 ts->realtime = now(CLOCK_REALTIME);
89 ts->monotonic = now(CLOCK_MONOTONIC);
90
91 return ts;
92}
93
60918275
LP
94usec_t timespec_load(const struct timespec *ts) {
95 assert(ts);
96
97 return
98 (usec_t) ts->tv_sec * USEC_PER_SEC +
99 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
100}
101
102struct timespec *timespec_store(struct timespec *ts, usec_t u) {
103 assert(ts);
104
105 ts->tv_sec = (time_t) (u / USEC_PER_SEC);
106 ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
107
108 return ts;
109}
110
111usec_t timeval_load(const struct timeval *tv) {
112 assert(tv);
113
114 return
115 (usec_t) tv->tv_sec * USEC_PER_SEC +
116 (usec_t) tv->tv_usec;
117}
118
119struct timeval *timeval_store(struct timeval *tv, usec_t u) {
120 assert(tv);
121
122 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
123 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
124
125 return tv;
126}
127
128bool endswith(const char *s, const char *postfix) {
129 size_t sl, pl;
130
131 assert(s);
132 assert(postfix);
133
134 sl = strlen(s);
135 pl = strlen(postfix);
136
d4d0d4db
LP
137 if (pl == 0)
138 return true;
139
60918275
LP
140 if (sl < pl)
141 return false;
142
143 return memcmp(s + sl - pl, postfix, pl) == 0;
144}
145
146bool startswith(const char *s, const char *prefix) {
147 size_t sl, pl;
148
149 assert(s);
150 assert(prefix);
151
152 sl = strlen(s);
153 pl = strlen(prefix);
154
d4d0d4db
LP
155 if (pl == 0)
156 return true;
157
60918275
LP
158 if (sl < pl)
159 return false;
160
161 return memcmp(s, prefix, pl) == 0;
162}
163
3177a7fa
MAP
164bool startswith_no_case(const char *s, const char *prefix) {
165 size_t sl, pl;
166 unsigned i;
167
168 assert(s);
169 assert(prefix);
170
171 sl = strlen(s);
172 pl = strlen(prefix);
173
174 if (pl == 0)
175 return true;
176
177 if (sl < pl)
178 return false;
179
180 for(i = 0; i < pl; ++i) {
181 if (tolower(s[i]) != tolower(prefix[i]))
182 return false;
183 }
184
185 return true;
186}
187
79d6d816
LP
188bool first_word(const char *s, const char *word) {
189 size_t sl, wl;
190
191 assert(s);
192 assert(word);
193
194 sl = strlen(s);
195 wl = strlen(word);
196
197 if (sl < wl)
198 return false;
199
d4d0d4db
LP
200 if (wl == 0)
201 return true;
202
79d6d816
LP
203 if (memcmp(s, word, wl) != 0)
204 return false;
205
d4d0d4db
LP
206 return s[wl] == 0 ||
207 strchr(WHITESPACE, s[wl]);
79d6d816
LP
208}
209
42f4e3c4 210int close_nointr(int fd) {
60918275
LP
211 assert(fd >= 0);
212
213 for (;;) {
214 int r;
215
216 if ((r = close(fd)) >= 0)
217 return r;
218
219 if (errno != EINTR)
220 return r;
221 }
222}
85261803 223
85f136b5 224void close_nointr_nofail(int fd) {
80876c20 225 int saved_errno = errno;
85f136b5
LP
226
227 /* like close_nointr() but cannot fail, and guarantees errno
228 * is unchanged */
229
230 assert_se(close_nointr(fd) == 0);
80876c20
LP
231
232 errno = saved_errno;
85f136b5
LP
233}
234
5b6319dc
LP
235void close_many(const int fds[], unsigned n_fd) {
236 unsigned i;
237
238 for (i = 0; i < n_fd; i++)
239 close_nointr_nofail(fds[i]);
240}
241
85261803
LP
242int parse_boolean(const char *v) {
243 assert(v);
244
44d8db9e 245 if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
85261803 246 return 1;
44d8db9e 247 else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
85261803
LP
248 return 0;
249
250 return -EINVAL;
251}
252
3ba686c1 253int parse_pid(const char *s, pid_t* ret_pid) {
0b172489 254 unsigned long ul = 0;
3ba686c1
LP
255 pid_t pid;
256 int r;
257
258 assert(s);
259 assert(ret_pid);
260
261 if ((r = safe_atolu(s, &ul)) < 0)
262 return r;
263
264 pid = (pid_t) ul;
265
266 if ((unsigned long) pid != ul)
267 return -ERANGE;
268
269 if (pid <= 0)
270 return -ERANGE;
271
272 *ret_pid = pid;
273 return 0;
274}
275
85261803
LP
276int safe_atou(const char *s, unsigned *ret_u) {
277 char *x = NULL;
034c6ed7 278 unsigned long l;
85261803
LP
279
280 assert(s);
281 assert(ret_u);
282
283 errno = 0;
284 l = strtoul(s, &x, 0);
285
286 if (!x || *x || errno)
287 return errno ? -errno : -EINVAL;
288
034c6ed7 289 if ((unsigned long) (unsigned) l != l)
85261803
LP
290 return -ERANGE;
291
292 *ret_u = (unsigned) l;
293 return 0;
294}
295
296int safe_atoi(const char *s, int *ret_i) {
297 char *x = NULL;
034c6ed7 298 long l;
85261803
LP
299
300 assert(s);
301 assert(ret_i);
302
303 errno = 0;
304 l = strtol(s, &x, 0);
305
306 if (!x || *x || errno)
307 return errno ? -errno : -EINVAL;
308
034c6ed7 309 if ((long) (int) l != l)
85261803
LP
310 return -ERANGE;
311
034c6ed7
LP
312 *ret_i = (int) l;
313 return 0;
314}
315
034c6ed7
LP
316int safe_atollu(const char *s, long long unsigned *ret_llu) {
317 char *x = NULL;
318 unsigned long long l;
319
320 assert(s);
321 assert(ret_llu);
322
323 errno = 0;
324 l = strtoull(s, &x, 0);
325
326 if (!x || *x || errno)
327 return errno ? -errno : -EINVAL;
328
329 *ret_llu = l;
330 return 0;
331}
332
333int safe_atolli(const char *s, long long int *ret_lli) {
334 char *x = NULL;
335 long long l;
336
337 assert(s);
338 assert(ret_lli);
339
340 errno = 0;
341 l = strtoll(s, &x, 0);
342
343 if (!x || *x || errno)
344 return errno ? -errno : -EINVAL;
345
346 *ret_lli = l;
85261803
LP
347 return 0;
348}
a41e8209 349
a41e8209 350/* Split a string into words. */
65d2ebdc 351char *split(const char *c, size_t *l, const char *separator, char **state) {
a41e8209
LP
352 char *current;
353
354 current = *state ? *state : (char*) c;
355
356 if (!*current || *c == 0)
357 return NULL;
358
65d2ebdc
LP
359 current += strspn(current, separator);
360 *l = strcspn(current, separator);
82919e3d
LP
361 *state = current+*l;
362
363 return (char*) current;
364}
365
034c6ed7
LP
366/* Split a string into words, but consider strings enclosed in '' and
367 * "" as words even if they include spaces. */
368char *split_quoted(const char *c, size_t *l, char **state) {
0bab36f2
LP
369 char *current, *e;
370 bool escaped = false;
034c6ed7
LP
371
372 current = *state ? *state : (char*) c;
373
374 if (!*current || *c == 0)
375 return NULL;
376
377 current += strspn(current, WHITESPACE);
378
379 if (*current == '\'') {
380 current ++;
034c6ed7 381
0bab36f2
LP
382 for (e = current; *e; e++) {
383 if (escaped)
384 escaped = false;
385 else if (*e == '\\')
386 escaped = true;
387 else if (*e == '\'')
388 break;
389 }
390
391 *l = e-current;
392 *state = *e == 0 ? e : e+1;
034c6ed7
LP
393 } else if (*current == '\"') {
394 current ++;
034c6ed7 395
0bab36f2
LP
396 for (e = current; *e; e++) {
397 if (escaped)
398 escaped = false;
399 else if (*e == '\\')
400 escaped = true;
401 else if (*e == '\"')
402 break;
403 }
404
405 *l = e-current;
406 *state = *e == 0 ? e : e+1;
034c6ed7 407 } else {
0bab36f2
LP
408 for (e = current; *e; e++) {
409 if (escaped)
410 escaped = false;
411 else if (*e == '\\')
412 escaped = true;
413 else if (strchr(WHITESPACE, *e))
414 break;
415 }
416 *l = e-current;
417 *state = e;
034c6ed7
LP
418 }
419
420 return (char*) current;
421}
422
65d2ebdc
LP
423char **split_path_and_make_absolute(const char *p) {
424 char **l;
425 assert(p);
426
427 if (!(l = strv_split(p, ":")))
428 return NULL;
429
430 if (!strv_path_make_absolute_cwd(l)) {
431 strv_free(l);
432 return NULL;
433 }
434
435 return l;
436}
437
034c6ed7
LP
438int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
439 int r;
440 FILE *f;
441 char fn[132], line[256], *p;
bb00e604 442 long unsigned ppid;
034c6ed7
LP
443
444 assert(pid >= 0);
445 assert(_ppid);
446
bb00e604 447 assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%lu/stat", (unsigned long) pid) < (int) (sizeof(fn)-1));
034c6ed7
LP
448 fn[sizeof(fn)-1] = 0;
449
450 if (!(f = fopen(fn, "r")))
451 return -errno;
452
453 if (!(fgets(line, sizeof(line), f))) {
454 r = -errno;
455 fclose(f);
456 return r;
457 }
458
459 fclose(f);
460
461 /* Let's skip the pid and comm fields. The latter is enclosed
462 * in () but does not escape any () in its value, so let's
463 * skip over it manually */
464
465 if (!(p = strrchr(line, ')')))
466 return -EIO;
467
468 p++;
469
470 if (sscanf(p, " "
471 "%*c " /* state */
bb00e604 472 "%lu ", /* ppid */
034c6ed7
LP
473 &ppid) != 1)
474 return -EIO;
475
bb00e604 476 if ((long unsigned) (pid_t) ppid != ppid)
034c6ed7
LP
477 return -ERANGE;
478
479 *_ppid = (pid_t) ppid;
480
481 return 0;
482}
483
484int write_one_line_file(const char *fn, const char *line) {
485 FILE *f;
486 int r;
487
488 assert(fn);
489 assert(line);
490
491 if (!(f = fopen(fn, "we")))
492 return -errno;
493
494 if (fputs(line, f) < 0) {
495 r = -errno;
496 goto finish;
497 }
498
8e1bd70d
LP
499 if (!endswith(line, "\n"))
500 fputc('\n', f);
501
034c6ed7
LP
502 r = 0;
503finish:
504 fclose(f);
505 return r;
506}
507
508int read_one_line_file(const char *fn, char **line) {
509 FILE *f;
510 int r;
97c4a07d 511 char t[LINE_MAX], *c;
034c6ed7
LP
512
513 assert(fn);
514 assert(line);
515
516 if (!(f = fopen(fn, "re")))
517 return -errno;
518
519 if (!(fgets(t, sizeof(t), f))) {
520 r = -errno;
521 goto finish;
522 }
523
524 if (!(c = strdup(t))) {
525 r = -ENOMEM;
526 goto finish;
527 }
528
529 *line = c;
530 r = 0;
531
532finish:
533 fclose(f);
534 return r;
535}
44d8db9e 536
97c4a07d
LP
537int read_full_file(const char *fn, char **contents) {
538 FILE *f;
539 int r;
540 size_t n, l;
541 char *buf = NULL;
542 struct stat st;
543
544 if (!(f = fopen(fn, "re")))
545 return -errno;
546
547 if (fstat(fileno(f), &st) < 0) {
548 r = -errno;
549 goto finish;
550 }
551
552 n = st.st_size > 0 ? st.st_size : LINE_MAX;
553 l = 0;
554
555 for (;;) {
556 char *t;
557 size_t k;
558
559 if (!(t = realloc(buf, n+1))) {
560 r = -ENOMEM;
561 goto finish;
562 }
563
564 buf = t;
565 k = fread(buf + l, 1, n - l, f);
566
567 if (k <= 0) {
568 if (ferror(f)) {
569 r = -errno;
570 goto finish;
571 }
572
573 break;
574 }
575
576 l += k;
577 n *= 2;
578
579 /* Safety check */
580 if (n > 4*1024*1024) {
581 r = -E2BIG;
582 goto finish;
583 }
584 }
585
586 if (buf)
587 buf[l] = 0;
588 else if (!(buf = calloc(1, 1))) {
589 r = -errno;
590 goto finish;
591 }
592
593 *contents = buf;
594 buf = NULL;
595
596 r = 0;
597
598finish:
599 fclose(f);
600 free(buf);
601
602 return r;
603}
604
605int parse_env_file(
606 const char *fname,
c899f8c6 607 const char *separator, ...) {
97c4a07d 608
ce8a6aa1 609 int r = 0;
97c4a07d
LP
610 char *contents, *p;
611
612 assert(fname);
c899f8c6 613 assert(separator);
97c4a07d
LP
614
615 if ((r = read_full_file(fname, &contents)) < 0)
616 return r;
617
618 p = contents;
619 for (;;) {
620 const char *key = NULL;
621
c899f8c6 622 p += strspn(p, separator);
97c4a07d
LP
623 p += strspn(p, WHITESPACE);
624
625 if (!*p)
626 break;
627
628 if (!strchr(COMMENTS, *p)) {
629 va_list ap;
630 char **value;
631
c899f8c6 632 va_start(ap, separator);
97c4a07d
LP
633 while ((key = va_arg(ap, char *))) {
634 size_t n;
635 char *v;
636
637 value = va_arg(ap, char **);
638
639 n = strlen(key);
640 if (strncmp(p, key, n) != 0 ||
641 p[n] != '=')
642 continue;
643
644 p += n + 1;
c899f8c6 645 n = strcspn(p, separator);
97c4a07d
LP
646
647 if (n >= 2 &&
e7db37dd
LP
648 strchr(QUOTES, p[0]) &&
649 p[n-1] == p[0])
97c4a07d
LP
650 v = strndup(p+1, n-2);
651 else
652 v = strndup(p, n);
653
654 if (!v) {
655 r = -ENOMEM;
656 va_end(ap);
657 goto fail;
658 }
659
dd36de4d
KS
660 if (v[0] == '\0') {
661 /* return empty value strings as NULL */
662 free(v);
663 v = NULL;
664 }
665
97c4a07d
LP
666 free(*value);
667 *value = v;
668
669 p += n;
ce8a6aa1
LP
670
671 r ++;
97c4a07d
LP
672 break;
673 }
674 va_end(ap);
675 }
676
677 if (!key)
c899f8c6 678 p += strcspn(p, separator);
97c4a07d
LP
679 }
680
97c4a07d
LP
681fail:
682 free(contents);
683 return r;
684}
685
8c7be95e
LP
686int load_env_file(
687 const char *fname,
688 char ***rl) {
689
690 FILE *f;
691 char **m = 0;
692 int r;
693
694 assert(fname);
695 assert(rl);
696
697 if (!(f = fopen(fname, "re")))
698 return -errno;
699
700 while (!feof(f)) {
701 char l[LINE_MAX], *p, *u;
702 char **t;
703
704 if (!fgets(l, sizeof(l), f)) {
705 if (feof(f))
706 break;
707
708 r = -errno;
709 goto finish;
710 }
711
712 p = strstrip(l);
713
714 if (!*p)
715 continue;
716
717 if (strchr(COMMENTS, *p))
718 continue;
719
720 if (!(u = normalize_env_assignment(p))) {
721 log_error("Out of memory");
722 r = -ENOMEM;
723 goto finish;
724 }
725
726 t = strv_append(m, u);
727 free(u);
728
729 if (!t) {
730 log_error("Out of memory");
731 r = -ENOMEM;
732 goto finish;
733 }
734
735 strv_free(m);
736 m = t;
737 }
738
739 r = 0;
740
741 *rl = m;
742 m = NULL;
743
744finish:
745 if (f)
746 fclose(f);
747
748 strv_free(m);
749
750 return r;
751}
752
7072ced8
LP
753char *truncate_nl(char *s) {
754 assert(s);
755
756 s[strcspn(s, NEWLINE)] = 0;
757 return s;
758}
759
760int get_process_name(pid_t pid, char **name) {
761 char *p;
762 int r;
763
764 assert(pid >= 1);
765 assert(name);
766
bb00e604 767 if (asprintf(&p, "/proc/%lu/comm", (unsigned long) pid) < 0)
7072ced8
LP
768 return -ENOMEM;
769
770 r = read_one_line_file(p, name);
771 free(p);
772
773 if (r < 0)
774 return r;
775
776 truncate_nl(*name);
777 return 0;
778}
779
c59760ee
LP
780int get_process_cmdline(pid_t pid, size_t max_length, char **line) {
781 char *p, *r, *k;
782 int c;
783 bool space = false;
784 size_t left;
785 FILE *f;
786
787 assert(pid >= 1);
788 assert(max_length > 0);
789 assert(line);
790
791 if (asprintf(&p, "/proc/%lu/cmdline", (unsigned long) pid) < 0)
792 return -ENOMEM;
793
794 f = fopen(p, "r");
795 free(p);
796
797 if (!f)
798 return -errno;
799
800 if (!(r = new(char, max_length))) {
801 fclose(f);
802 return -ENOMEM;
803 }
804
805 k = r;
806 left = max_length;
807 while ((c = getc(f)) != EOF) {
808
809 if (isprint(c)) {
810 if (space) {
811 if (left <= 4)
812 break;
813
814 *(k++) = ' ';
057fbb58 815 left--;
c59760ee
LP
816 space = false;
817 }
818
819 if (left <= 4)
820 break;
821
822 *(k++) = (char) c;
057fbb58 823 left--;
c59760ee
LP
824 } else
825 space = true;
826 }
827
828 if (left <= 4) {
829 size_t n = MIN(left-1, 3U);
830 memcpy(k, "...", n);
831 k[n] = 0;
832 } else
833 *k = 0;
834
835 fclose(f);
836
35d2e7ec
LP
837 /* Kernel threads have no argv[] */
838 if (r[0] == 0) {
839 char *t;
840 int h;
841
842 free(r);
843
844 if ((h = get_process_name(pid, &t)) < 0)
845 return h;
846
847 h = asprintf(&r, "[%s]", t);
848 free(t);
849
850 if (h < 0)
851 return -ENOMEM;
852 }
fa776d8e 853
c59760ee
LP
854 *line = r;
855 return 0;
856}
857
fab56fc5
LP
858char *strnappend(const char *s, const char *suffix, size_t b) {
859 size_t a;
44d8db9e
LP
860 char *r;
861
fab56fc5
LP
862 if (!s && !suffix)
863 return strdup("");
864
865 if (!s)
866 return strndup(suffix, b);
867
868 if (!suffix)
869 return strdup(s);
870
44d8db9e
LP
871 assert(s);
872 assert(suffix);
873
874 a = strlen(s);
44d8db9e
LP
875
876 if (!(r = new(char, a+b+1)))
877 return NULL;
878
879 memcpy(r, s, a);
880 memcpy(r+a, suffix, b);
881 r[a+b] = 0;
882
883 return r;
884}
87f0e418 885
fab56fc5
LP
886char *strappend(const char *s, const char *suffix) {
887 return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
888}
889
87f0e418
LP
890int readlink_malloc(const char *p, char **r) {
891 size_t l = 100;
892
893 assert(p);
894 assert(r);
895
896 for (;;) {
897 char *c;
898 ssize_t n;
899
900 if (!(c = new(char, l)))
901 return -ENOMEM;
902
903 if ((n = readlink(p, c, l-1)) < 0) {
904 int ret = -errno;
905 free(c);
906 return ret;
907 }
908
909 if ((size_t) n < l-1) {
910 c[n] = 0;
911 *r = c;
912 return 0;
913 }
914
915 free(c);
916 l *= 2;
917 }
918}
919
2c7108c4
LP
920int readlink_and_make_absolute(const char *p, char **r) {
921 char *target, *k;
922 int j;
923
924 assert(p);
925 assert(r);
926
927 if ((j = readlink_malloc(p, &target)) < 0)
928 return j;
929
930 k = file_in_same_dir(p, target);
931 free(target);
932
933 if (!k)
934 return -ENOMEM;
935
936 *r = k;
937 return 0;
938}
939
35d2e7ec
LP
940int parent_of_path(const char *path, char **_r) {
941 const char *e, *a = NULL, *b = NULL, *p;
942 char *r;
943 bool slash = false;
944
945 assert(path);
946 assert(_r);
947
948 if (!*path)
949 return -EINVAL;
950
951 for (e = path; *e; e++) {
952
953 if (!slash && *e == '/') {
954 a = b;
955 b = e;
956 slash = true;
957 } else if (slash && *e != '/')
958 slash = false;
959 }
960
961 if (*(e-1) == '/')
962 p = a;
963 else
964 p = b;
965
966 if (!p)
967 return -EINVAL;
968
969 if (p == path)
970 r = strdup("/");
971 else
972 r = strndup(path, p-path);
973
974 if (!r)
975 return -ENOMEM;
976
977 *_r = r;
978 return 0;
979}
980
981
87f0e418
LP
982char *file_name_from_path(const char *p) {
983 char *r;
984
985 assert(p);
986
987 if ((r = strrchr(p, '/')))
988 return r + 1;
989
990 return (char*) p;
991}
0301abf4
LP
992
993bool path_is_absolute(const char *p) {
994 assert(p);
995
996 return p[0] == '/';
997}
998
999bool is_path(const char *p) {
1000
1001 return !!strchr(p, '/');
1002}
1003
1004char *path_make_absolute(const char *p, const char *prefix) {
1005 char *r;
1006
1007 assert(p);
1008
65d2ebdc
LP
1009 /* Makes every item in the list an absolute path by prepending
1010 * the prefix, if specified and necessary */
1011
0301abf4
LP
1012 if (path_is_absolute(p) || !prefix)
1013 return strdup(p);
1014
1015 if (asprintf(&r, "%s/%s", prefix, p) < 0)
1016 return NULL;
1017
1018 return r;
1019}
2a987ee8 1020
65d2ebdc
LP
1021char *path_make_absolute_cwd(const char *p) {
1022 char *cwd, *r;
1023
1024 assert(p);
1025
1026 /* Similar to path_make_absolute(), but prefixes with the
1027 * current working directory. */
1028
1029 if (path_is_absolute(p))
1030 return strdup(p);
1031
1032 if (!(cwd = get_current_dir_name()))
1033 return NULL;
1034
1035 r = path_make_absolute(p, cwd);
1036 free(cwd);
1037
1038 return r;
1039}
1040
1041char **strv_path_make_absolute_cwd(char **l) {
1042 char **s;
1043
1044 /* Goes through every item in the string list and makes it
1045 * absolute. This works in place and won't rollback any
1046 * changes on failure. */
1047
1048 STRV_FOREACH(s, l) {
1049 char *t;
1050
1051 if (!(t = path_make_absolute_cwd(*s)))
1052 return NULL;
1053
1054 free(*s);
1055 *s = t;
1056 }
1057
1058 return l;
1059}
1060
c3f6d675
LP
1061char **strv_path_canonicalize(char **l) {
1062 char **s;
1063 unsigned k = 0;
1064 bool enomem = false;
1065
1066 if (strv_isempty(l))
1067 return l;
1068
1069 /* Goes through every item in the string list and canonicalize
1070 * the path. This works in place and won't rollback any
1071 * changes on failure. */
1072
1073 STRV_FOREACH(s, l) {
1074 char *t, *u;
1075
1076 t = path_make_absolute_cwd(*s);
1077 free(*s);
1078
1079 if (!t) {
1080 enomem = true;
1081 continue;
1082 }
1083
1084 errno = 0;
1085 u = canonicalize_file_name(t);
1086 free(t);
1087
1088 if (!u) {
1089 if (errno == ENOMEM || !errno)
1090 enomem = true;
1091
1092 continue;
1093 }
1094
1095 l[k++] = u;
1096 }
1097
1098 l[k] = NULL;
1099
1100 if (enomem)
1101 return NULL;
1102
1103 return l;
1104}
1105
2a987ee8
LP
1106int reset_all_signal_handlers(void) {
1107 int sig;
1108
1109 for (sig = 1; sig < _NSIG; sig++) {
1110 struct sigaction sa;
1111
1112 if (sig == SIGKILL || sig == SIGSTOP)
1113 continue;
1114
1115 zero(sa);
1116 sa.sa_handler = SIG_DFL;
431c32bf 1117 sa.sa_flags = SA_RESTART;
2a987ee8
LP
1118
1119 /* On Linux the first two RT signals are reserved by
1120 * glibc, and sigaction() will return EINVAL for them. */
1121 if ((sigaction(sig, &sa, NULL) < 0))
1122 if (errno != EINVAL)
1123 return -errno;
1124 }
1125
8e274523 1126 return 0;
2a987ee8 1127}
4a72ff34
LP
1128
1129char *strstrip(char *s) {
1130 char *e, *l = NULL;
1131
1132 /* Drops trailing whitespace. Modifies the string in
1133 * place. Returns pointer to first non-space character */
1134
1135 s += strspn(s, WHITESPACE);
1136
1137 for (e = s; *e; e++)
1138 if (!strchr(WHITESPACE, *e))
1139 l = e;
1140
1141 if (l)
1142 *(l+1) = 0;
1143 else
1144 *s = 0;
1145
1146 return s;
4a72ff34
LP
1147}
1148
ee9b5e01
LP
1149char *delete_chars(char *s, const char *bad) {
1150 char *f, *t;
1151
1152 /* Drops all whitespace, regardless where in the string */
1153
1154 for (f = s, t = s; *f; f++) {
1155 if (strchr(bad, *f))
1156 continue;
1157
1158 *(t++) = *f;
1159 }
1160
1161 *t = 0;
1162
1163 return s;
1164}
1165
4a72ff34
LP
1166char *file_in_same_dir(const char *path, const char *filename) {
1167 char *e, *r;
1168 size_t k;
1169
1170 assert(path);
1171 assert(filename);
1172
1173 /* This removes the last component of path and appends
1174 * filename, unless the latter is absolute anyway or the
1175 * former isn't */
1176
1177 if (path_is_absolute(filename))
1178 return strdup(filename);
1179
1180 if (!(e = strrchr(path, '/')))
1181 return strdup(filename);
1182
1183 k = strlen(filename);
1184 if (!(r = new(char, e-path+1+k+1)))
1185 return NULL;
1186
1187 memcpy(r, path, e-path+1);
1188 memcpy(r+(e-path)+1, filename, k+1);
1189
1190 return r;
1191}
fb624d04 1192
8c6db833
LP
1193int safe_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid) {
1194 struct stat st;
1195
56cf987f 1196 if (label_mkdir(path, mode) >= 0)
8c6db833
LP
1197 if (chmod_and_chown(path, mode, uid, gid) < 0)
1198 return -errno;
1199
1200 if (lstat(path, &st) < 0)
1201 return -errno;
1202
1203 if ((st.st_mode & 0777) != mode ||
1204 st.st_uid != uid ||
1205 st.st_gid != gid ||
1206 !S_ISDIR(st.st_mode)) {
1207 errno = EEXIST;
1208 return -errno;
1209 }
1210
1211 return 0;
1212}
1213
1214
a9f5d454
LP
1215int mkdir_parents(const char *path, mode_t mode) {
1216 const char *p, *e;
1217
1218 assert(path);
1219
1220 /* Creates every parent directory in the path except the last
1221 * component. */
1222
1223 p = path + strspn(path, "/");
1224 for (;;) {
1225 int r;
1226 char *t;
1227
1228 e = p + strcspn(p, "/");
1229 p = e + strspn(e, "/");
1230
1231 /* Is this the last component? If so, then we're
1232 * done */
1233 if (*p == 0)
1234 return 0;
1235
1236 if (!(t = strndup(path, e - path)))
1237 return -ENOMEM;
1238
56cf987f 1239 r = label_mkdir(t, mode);
a9f5d454
LP
1240 free(t);
1241
1242 if (r < 0 && errno != EEXIST)
1243 return -errno;
1244 }
1245}
1246
bbd67135
LP
1247int mkdir_p(const char *path, mode_t mode) {
1248 int r;
1249
1250 /* Like mkdir -p */
1251
1252 if ((r = mkdir_parents(path, mode)) < 0)
1253 return r;
1254
56cf987f 1255 if (label_mkdir(path, mode) < 0 && errno != EEXIST)
bbd67135
LP
1256 return -errno;
1257
1258 return 0;
1259}
1260
c32dd69b
LP
1261int rmdir_parents(const char *path, const char *stop) {
1262 size_t l;
1263 int r = 0;
1264
1265 assert(path);
1266 assert(stop);
1267
1268 l = strlen(path);
1269
1270 /* Skip trailing slashes */
1271 while (l > 0 && path[l-1] == '/')
1272 l--;
1273
1274 while (l > 0) {
1275 char *t;
1276
1277 /* Skip last component */
1278 while (l > 0 && path[l-1] != '/')
1279 l--;
1280
1281 /* Skip trailing slashes */
1282 while (l > 0 && path[l-1] == '/')
1283 l--;
1284
1285 if (l <= 0)
1286 break;
1287
1288 if (!(t = strndup(path, l)))
1289 return -ENOMEM;
1290
1291 if (path_startswith(stop, t)) {
1292 free(t);
1293 return 0;
1294 }
1295
1296 r = rmdir(t);
1297 free(t);
1298
1299 if (r < 0)
1300 if (errno != ENOENT)
1301 return -errno;
1302 }
1303
1304 return 0;
1305}
1306
1307
fb624d04
LP
1308char hexchar(int x) {
1309 static const char table[16] = "0123456789abcdef";
1310
1311 return table[x & 15];
1312}
4fe88d28
LP
1313
1314int unhexchar(char c) {
1315
1316 if (c >= '0' && c <= '9')
1317 return c - '0';
1318
1319 if (c >= 'a' && c <= 'f')
ea430986 1320 return c - 'a' + 10;
4fe88d28
LP
1321
1322 if (c >= 'A' && c <= 'F')
ea430986 1323 return c - 'A' + 10;
4fe88d28
LP
1324
1325 return -1;
1326}
1327
1328char octchar(int x) {
1329 return '0' + (x & 7);
1330}
1331
1332int unoctchar(char c) {
1333
1334 if (c >= '0' && c <= '7')
1335 return c - '0';
1336
1337 return -1;
1338}
1339
5af98f82
LP
1340char decchar(int x) {
1341 return '0' + (x % 10);
1342}
1343
1344int undecchar(char c) {
1345
1346 if (c >= '0' && c <= '9')
1347 return c - '0';
1348
1349 return -1;
1350}
1351
4fe88d28
LP
1352char *cescape(const char *s) {
1353 char *r, *t;
1354 const char *f;
1355
1356 assert(s);
1357
1358 /* Does C style string escaping. */
1359
1360 if (!(r = new(char, strlen(s)*4 + 1)))
1361 return NULL;
1362
1363 for (f = s, t = r; *f; f++)
1364
1365 switch (*f) {
1366
1367 case '\a':
1368 *(t++) = '\\';
1369 *(t++) = 'a';
1370 break;
1371 case '\b':
1372 *(t++) = '\\';
1373 *(t++) = 'b';
1374 break;
1375 case '\f':
1376 *(t++) = '\\';
1377 *(t++) = 'f';
1378 break;
1379 case '\n':
1380 *(t++) = '\\';
1381 *(t++) = 'n';
1382 break;
1383 case '\r':
1384 *(t++) = '\\';
1385 *(t++) = 'r';
1386 break;
1387 case '\t':
1388 *(t++) = '\\';
1389 *(t++) = 't';
1390 break;
1391 case '\v':
1392 *(t++) = '\\';
1393 *(t++) = 'v';
1394 break;
1395 case '\\':
1396 *(t++) = '\\';
1397 *(t++) = '\\';
1398 break;
1399 case '"':
1400 *(t++) = '\\';
1401 *(t++) = '"';
1402 break;
1403 case '\'':
1404 *(t++) = '\\';
1405 *(t++) = '\'';
1406 break;
1407
1408 default:
1409 /* For special chars we prefer octal over
1410 * hexadecimal encoding, simply because glib's
1411 * g_strescape() does the same */
1412 if ((*f < ' ') || (*f >= 127)) {
1413 *(t++) = '\\';
1414 *(t++) = octchar((unsigned char) *f >> 6);
1415 *(t++) = octchar((unsigned char) *f >> 3);
1416 *(t++) = octchar((unsigned char) *f);
1417 } else
1418 *(t++) = *f;
1419 break;
1420 }
1421
1422 *t = 0;
1423
1424 return r;
1425}
1426
6febfd0d 1427char *cunescape_length(const char *s, size_t length) {
4fe88d28
LP
1428 char *r, *t;
1429 const char *f;
1430
1431 assert(s);
1432
1433 /* Undoes C style string escaping */
1434
6febfd0d 1435 if (!(r = new(char, length+1)))
4fe88d28
LP
1436 return r;
1437
6febfd0d 1438 for (f = s, t = r; f < s + length; f++) {
4fe88d28
LP
1439
1440 if (*f != '\\') {
1441 *(t++) = *f;
1442 continue;
1443 }
1444
1445 f++;
1446
1447 switch (*f) {
1448
1449 case 'a':
1450 *(t++) = '\a';
1451 break;
1452 case 'b':
1453 *(t++) = '\b';
1454 break;
1455 case 'f':
1456 *(t++) = '\f';
1457 break;
1458 case 'n':
1459 *(t++) = '\n';
1460 break;
1461 case 'r':
1462 *(t++) = '\r';
1463 break;
1464 case 't':
1465 *(t++) = '\t';
1466 break;
1467 case 'v':
1468 *(t++) = '\v';
1469 break;
1470 case '\\':
1471 *(t++) = '\\';
1472 break;
1473 case '"':
1474 *(t++) = '"';
1475 break;
1476 case '\'':
1477 *(t++) = '\'';
1478 break;
1479
e167fb86
LP
1480 case 's':
1481 /* This is an extension of the XDG syntax files */
1482 *(t++) = ' ';
1483 break;
1484
4fe88d28
LP
1485 case 'x': {
1486 /* hexadecimal encoding */
1487 int a, b;
1488
1489 if ((a = unhexchar(f[1])) < 0 ||
1490 (b = unhexchar(f[2])) < 0) {
1491 /* Invalid escape code, let's take it literal then */
1492 *(t++) = '\\';
1493 *(t++) = 'x';
1494 } else {
1495 *(t++) = (char) ((a << 4) | b);
1496 f += 2;
1497 }
1498
1499 break;
1500 }
1501
1502 case '0':
1503 case '1':
1504 case '2':
1505 case '3':
1506 case '4':
1507 case '5':
1508 case '6':
1509 case '7': {
1510 /* octal encoding */
1511 int a, b, c;
1512
1513 if ((a = unoctchar(f[0])) < 0 ||
1514 (b = unoctchar(f[1])) < 0 ||
1515 (c = unoctchar(f[2])) < 0) {
1516 /* Invalid escape code, let's take it literal then */
1517 *(t++) = '\\';
1518 *(t++) = f[0];
1519 } else {
1520 *(t++) = (char) ((a << 6) | (b << 3) | c);
1521 f += 2;
1522 }
1523
1524 break;
1525 }
1526
1527 case 0:
1528 /* premature end of string.*/
1529 *(t++) = '\\';
1530 goto finish;
1531
1532 default:
1533 /* Invalid escape code, let's take it literal then */
1534 *(t++) = '\\';
f3d4cc01 1535 *(t++) = *f;
4fe88d28
LP
1536 break;
1537 }
1538 }
1539
1540finish:
1541 *t = 0;
1542 return r;
1543}
1544
6febfd0d
LP
1545char *cunescape(const char *s) {
1546 return cunescape_length(s, strlen(s));
1547}
4fe88d28
LP
1548
1549char *xescape(const char *s, const char *bad) {
1550 char *r, *t;
1551 const char *f;
1552
1553 /* Escapes all chars in bad, in addition to \ and all special
1554 * chars, in \xFF style escaping. May be reversed with
1555 * cunescape. */
1556
1557 if (!(r = new(char, strlen(s)*4+1)))
1558 return NULL;
1559
1560 for (f = s, t = r; *f; f++) {
1561
b866264a
LP
1562 if ((*f < ' ') || (*f >= 127) ||
1563 (*f == '\\') || strchr(bad, *f)) {
4fe88d28
LP
1564 *(t++) = '\\';
1565 *(t++) = 'x';
1566 *(t++) = hexchar(*f >> 4);
1567 *(t++) = hexchar(*f);
1568 } else
1569 *(t++) = *f;
1570 }
1571
1572 *t = 0;
1573
1574 return r;
1575}
1576
ea430986 1577char *bus_path_escape(const char *s) {
ea430986
LP
1578 char *r, *t;
1579 const char *f;
1580
47be870b
LP
1581 assert(s);
1582
ea430986
LP
1583 /* Escapes all chars that D-Bus' object path cannot deal
1584 * with. Can be reverse with bus_path_unescape() */
1585
1586 if (!(r = new(char, strlen(s)*3+1)))
1587 return NULL;
1588
1589 for (f = s, t = r; *f; f++) {
1590
1591 if (!(*f >= 'A' && *f <= 'Z') &&
1592 !(*f >= 'a' && *f <= 'z') &&
1593 !(*f >= '0' && *f <= '9')) {
1594 *(t++) = '_';
1595 *(t++) = hexchar(*f >> 4);
1596 *(t++) = hexchar(*f);
1597 } else
1598 *(t++) = *f;
1599 }
1600
1601 *t = 0;
1602
1603 return r;
1604}
1605
9e2f7c11 1606char *bus_path_unescape(const char *f) {
ea430986 1607 char *r, *t;
ea430986 1608
9e2f7c11 1609 assert(f);
47be870b 1610
9e2f7c11 1611 if (!(r = strdup(f)))
ea430986
LP
1612 return NULL;
1613
9e2f7c11 1614 for (t = r; *f; f++) {
ea430986
LP
1615
1616 if (*f == '_') {
1617 int a, b;
1618
1619 if ((a = unhexchar(f[1])) < 0 ||
1620 (b = unhexchar(f[2])) < 0) {
1621 /* Invalid escape code, let's take it literal then */
1622 *(t++) = '_';
1623 } else {
1624 *(t++) = (char) ((a << 4) | b);
1625 f += 2;
1626 }
1627 } else
1628 *(t++) = *f;
1629 }
1630
1631 *t = 0;
1632
1633 return r;
1634}
1635
4fe88d28
LP
1636char *path_kill_slashes(char *path) {
1637 char *f, *t;
1638 bool slash = false;
1639
1640 /* Removes redundant inner and trailing slashes. Modifies the
1641 * passed string in-place.
1642 *
1643 * ///foo///bar/ becomes /foo/bar
1644 */
1645
1646 for (f = path, t = path; *f; f++) {
1647
1648 if (*f == '/') {
1649 slash = true;
1650 continue;
1651 }
1652
1653 if (slash) {
1654 slash = false;
1655 *(t++) = '/';
1656 }
1657
1658 *(t++) = *f;
1659 }
1660
1661 /* Special rule, if we are talking of the root directory, a
1662 trailing slash is good */
1663
1664 if (t == path && slash)
1665 *(t++) = '/';
1666
1667 *t = 0;
1668 return path;
1669}
1670
1671bool path_startswith(const char *path, const char *prefix) {
1672 assert(path);
1673 assert(prefix);
1674
1675 if ((path[0] == '/') != (prefix[0] == '/'))
1676 return false;
1677
1678 for (;;) {
1679 size_t a, b;
1680
1681 path += strspn(path, "/");
1682 prefix += strspn(prefix, "/");
1683
1684 if (*prefix == 0)
1685 return true;
1686
1687 if (*path == 0)
1688 return false;
1689
1690 a = strcspn(path, "/");
1691 b = strcspn(prefix, "/");
1692
1693 if (a != b)
1694 return false;
1695
1696 if (memcmp(path, prefix, a) != 0)
1697 return false;
1698
1699 path += a;
1700 prefix += b;
1701 }
1702}
1703
15ae422b
LP
1704bool path_equal(const char *a, const char *b) {
1705 assert(a);
1706 assert(b);
1707
1708 if ((a[0] == '/') != (b[0] == '/'))
1709 return false;
1710
1711 for (;;) {
1712 size_t j, k;
1713
1714 a += strspn(a, "/");
1715 b += strspn(b, "/");
1716
1717 if (*a == 0 && *b == 0)
1718 return true;
1719
1720 if (*a == 0 || *b == 0)
1721 return false;
1722
1723 j = strcspn(a, "/");
1724 k = strcspn(b, "/");
1725
1726 if (j != k)
1727 return false;
1728
1729 if (memcmp(a, b, j) != 0)
1730 return false;
1731
1732 a += j;
1733 b += k;
1734 }
1735}
1736
67d51650 1737char *ascii_strlower(char *t) {
4fe88d28
LP
1738 char *p;
1739
67d51650 1740 assert(t);
4fe88d28 1741
67d51650 1742 for (p = t; *p; p++)
4fe88d28
LP
1743 if (*p >= 'A' && *p <= 'Z')
1744 *p = *p - 'A' + 'a';
1745
67d51650 1746 return t;
4fe88d28 1747}
1dccbe19 1748
c85dc17b
LP
1749bool ignore_file(const char *filename) {
1750 assert(filename);
1751
1752 return
1753 filename[0] == '.' ||
6c78be3c 1754 streq(filename, "lost+found") ||
e472d476
LP
1755 streq(filename, "aquota.user") ||
1756 streq(filename, "aquota.group") ||
c85dc17b
LP
1757 endswith(filename, "~") ||
1758 endswith(filename, ".rpmnew") ||
1759 endswith(filename, ".rpmsave") ||
1760 endswith(filename, ".rpmorig") ||
1761 endswith(filename, ".dpkg-old") ||
1762 endswith(filename, ".dpkg-new") ||
1763 endswith(filename, ".swp");
1764}
1765
3a0ecb08
LP
1766int fd_nonblock(int fd, bool nonblock) {
1767 int flags;
1768
1769 assert(fd >= 0);
1770
1771 if ((flags = fcntl(fd, F_GETFL, 0)) < 0)
1772 return -errno;
1773
1774 if (nonblock)
1775 flags |= O_NONBLOCK;
1776 else
1777 flags &= ~O_NONBLOCK;
1778
1779 if (fcntl(fd, F_SETFL, flags) < 0)
1780 return -errno;
1781
1782 return 0;
1783}
1784
1785int fd_cloexec(int fd, bool cloexec) {
1786 int flags;
1787
1788 assert(fd >= 0);
1789
1790 if ((flags = fcntl(fd, F_GETFD, 0)) < 0)
1791 return -errno;
1792
1793 if (cloexec)
1794 flags |= FD_CLOEXEC;
1795 else
1796 flags &= ~FD_CLOEXEC;
1797
1798 if (fcntl(fd, F_SETFD, flags) < 0)
1799 return -errno;
1800
1801 return 0;
1802}
1803
a0d40ac5
LP
1804int close_all_fds(const int except[], unsigned n_except) {
1805 DIR *d;
1806 struct dirent *de;
1807 int r = 0;
1808
1809 if (!(d = opendir("/proc/self/fd")))
1810 return -errno;
1811
1812 while ((de = readdir(d))) {
a7610064 1813 int fd = -1;
a0d40ac5 1814
a16e1123 1815 if (ignore_file(de->d_name))
a0d40ac5
LP
1816 continue;
1817
720ce21d
LP
1818 if (safe_atoi(de->d_name, &fd) < 0)
1819 /* Let's better ignore this, just in case */
1820 continue;
a0d40ac5
LP
1821
1822 if (fd < 3)
1823 continue;
1824
1825 if (fd == dirfd(d))
1826 continue;
1827
1828 if (except) {
1829 bool found;
1830 unsigned i;
1831
1832 found = false;
1833 for (i = 0; i < n_except; i++)
1834 if (except[i] == fd) {
1835 found = true;
1836 break;
1837 }
1838
1839 if (found)
1840 continue;
1841 }
1842
720ce21d 1843 if (close_nointr(fd) < 0) {
2f357920 1844 /* Valgrind has its own FD and doesn't want to have it closed */
720ce21d
LP
1845 if (errno != EBADF && r == 0)
1846 r = -errno;
2f357920 1847 }
a0d40ac5
LP
1848 }
1849
a0d40ac5
LP
1850 closedir(d);
1851 return r;
1852}
1853
db12775d
LP
1854bool chars_intersect(const char *a, const char *b) {
1855 const char *p;
1856
1857 /* Returns true if any of the chars in a are in b. */
1858 for (p = a; *p; p++)
1859 if (strchr(b, *p))
1860 return true;
1861
1862 return false;
1863}
1864
8b6c7120
LP
1865char *format_timestamp(char *buf, size_t l, usec_t t) {
1866 struct tm tm;
1867 time_t sec;
1868
1869 assert(buf);
1870 assert(l > 0);
1871
1872 if (t <= 0)
1873 return NULL;
1874
f872ec33 1875 sec = (time_t) (t / USEC_PER_SEC);
8b6c7120
LP
1876
1877 if (strftime(buf, l, "%a, %d %b %Y %H:%M:%S %z", localtime_r(&sec, &tm)) <= 0)
1878 return NULL;
1879
1880 return buf;
1881}
1882
584be568
LP
1883char *format_timestamp_pretty(char *buf, size_t l, usec_t t) {
1884 usec_t n, d;
1885
1886 n = now(CLOCK_REALTIME);
1887
1888 if (t <= 0 || t > n || t + USEC_PER_DAY*7 <= t)
1889 return NULL;
1890
1891 d = n - t;
1892
1893 if (d >= USEC_PER_YEAR)
1894 snprintf(buf, l, "%llu years and %llu months ago",
1895 (unsigned long long) (d / USEC_PER_YEAR),
1896 (unsigned long long) ((d % USEC_PER_YEAR) / USEC_PER_MONTH));
1897 else if (d >= USEC_PER_MONTH)
1898 snprintf(buf, l, "%llu months and %llu days ago",
1899 (unsigned long long) (d / USEC_PER_MONTH),
1900 (unsigned long long) ((d % USEC_PER_MONTH) / USEC_PER_DAY));
1901 else if (d >= USEC_PER_WEEK)
1902 snprintf(buf, l, "%llu weeks and %llu days ago",
1903 (unsigned long long) (d / USEC_PER_WEEK),
1904 (unsigned long long) ((d % USEC_PER_WEEK) / USEC_PER_DAY));
1905 else if (d >= 2*USEC_PER_DAY)
1906 snprintf(buf, l, "%llu days ago", (unsigned long long) (d / USEC_PER_DAY));
1907 else if (d >= 25*USEC_PER_HOUR)
1908 snprintf(buf, l, "1 day and %lluh ago",
1909 (unsigned long long) ((d - USEC_PER_DAY) / USEC_PER_HOUR));
1910 else if (d >= 6*USEC_PER_HOUR)
1911 snprintf(buf, l, "%lluh ago",
1912 (unsigned long long) (d / USEC_PER_HOUR));
1913 else if (d >= USEC_PER_HOUR)
1914 snprintf(buf, l, "%lluh %llumin ago",
1915 (unsigned long long) (d / USEC_PER_HOUR),
1916 (unsigned long long) ((d % USEC_PER_HOUR) / USEC_PER_MINUTE));
1917 else if (d >= 5*USEC_PER_MINUTE)
1918 snprintf(buf, l, "%llumin ago",
1919 (unsigned long long) (d / USEC_PER_MINUTE));
1920 else if (d >= USEC_PER_MINUTE)
1921 snprintf(buf, l, "%llumin %llus ago",
1922 (unsigned long long) (d / USEC_PER_MINUTE),
1923 (unsigned long long) ((d % USEC_PER_MINUTE) / USEC_PER_SEC));
1924 else if (d >= USEC_PER_SEC)
1925 snprintf(buf, l, "%llus ago",
1926 (unsigned long long) (d / USEC_PER_SEC));
1927 else if (d >= USEC_PER_MSEC)
1928 snprintf(buf, l, "%llums ago",
1929 (unsigned long long) (d / USEC_PER_MSEC));
1930 else if (d > 0)
1931 snprintf(buf, l, "%lluus ago",
1932 (unsigned long long) d);
1933 else
1934 snprintf(buf, l, "now");
1935
1936 buf[l-1] = 0;
1937 return buf;
1938}
1939
871d7de4
LP
1940char *format_timespan(char *buf, size_t l, usec_t t) {
1941 static const struct {
1942 const char *suffix;
1943 usec_t usec;
1944 } table[] = {
1945 { "w", USEC_PER_WEEK },
1946 { "d", USEC_PER_DAY },
1947 { "h", USEC_PER_HOUR },
1948 { "min", USEC_PER_MINUTE },
1949 { "s", USEC_PER_SEC },
1950 { "ms", USEC_PER_MSEC },
1951 { "us", 1 },
1952 };
1953
1954 unsigned i;
1955 char *p = buf;
1956
1957 assert(buf);
1958 assert(l > 0);
1959
1960 if (t == (usec_t) -1)
1961 return NULL;
1962
4502d22c
LP
1963 if (t == 0) {
1964 snprintf(p, l, "0");
1965 p[l-1] = 0;
1966 return p;
1967 }
1968
871d7de4
LP
1969 /* The result of this function can be parsed with parse_usec */
1970
1971 for (i = 0; i < ELEMENTSOF(table); i++) {
1972 int k;
1973 size_t n;
1974
1975 if (t < table[i].usec)
1976 continue;
1977
1978 if (l <= 1)
1979 break;
1980
1981 k = snprintf(p, l, "%s%llu%s", p > buf ? " " : "", (unsigned long long) (t / table[i].usec), table[i].suffix);
1982 n = MIN((size_t) k, l);
1983
1984 l -= n;
1985 p += n;
1986
1987 t %= table[i].usec;
1988 }
1989
1990 *p = 0;
1991
1992 return buf;
1993}
1994
42856c10
LP
1995bool fstype_is_network(const char *fstype) {
1996 static const char * const table[] = {
1997 "cifs",
1998 "smbfs",
1999 "ncpfs",
2000 "nfs",
ca139f94
LP
2001 "nfs4",
2002 "gfs",
2003 "gfs2"
42856c10
LP
2004 };
2005
2006 unsigned i;
2007
2008 for (i = 0; i < ELEMENTSOF(table); i++)
2009 if (streq(table[i], fstype))
2010 return true;
2011
2012 return false;
2013}
2014
601f6a1e
LP
2015int chvt(int vt) {
2016 int fd, r = 0;
2017
2018 if ((fd = open("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0)
2019 return -errno;
2020
2021 if (vt < 0) {
2022 int tiocl[2] = {
2023 TIOCL_GETKMSGREDIRECT,
2024 0
2025 };
2026
2027 if (ioctl(fd, TIOCLINUX, tiocl) < 0)
2028 return -errno;
2029
2030 vt = tiocl[0] <= 0 ? 1 : tiocl[0];
2031 }
2032
2033 if (ioctl(fd, VT_ACTIVATE, vt) < 0)
2034 r = -errno;
2035
a16e1123 2036 close_nointr_nofail(r);
601f6a1e
LP
2037 return r;
2038}
2039
80876c20
LP
2040int read_one_char(FILE *f, char *ret, bool *need_nl) {
2041 struct termios old_termios, new_termios;
2042 char c;
2043 char line[1024];
2044
2045 assert(f);
2046 assert(ret);
2047
2048 if (tcgetattr(fileno(f), &old_termios) >= 0) {
2049 new_termios = old_termios;
2050
2051 new_termios.c_lflag &= ~ICANON;
2052 new_termios.c_cc[VMIN] = 1;
2053 new_termios.c_cc[VTIME] = 0;
2054
2055 if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) {
2056 size_t k;
2057
2058 k = fread(&c, 1, 1, f);
2059
2060 tcsetattr(fileno(f), TCSADRAIN, &old_termios);
2061
2062 if (k <= 0)
2063 return -EIO;
2064
2065 if (need_nl)
2066 *need_nl = c != '\n';
2067
2068 *ret = c;
2069 return 0;
2070 }
2071 }
2072
2073 if (!(fgets(line, sizeof(line), f)))
2074 return -EIO;
2075
2076 truncate_nl(line);
2077
2078 if (strlen(line) != 1)
2079 return -EBADMSG;
2080
2081 if (need_nl)
2082 *need_nl = false;
2083
2084 *ret = line[0];
2085 return 0;
2086}
2087
2088int ask(char *ret, const char *replies, const char *text, ...) {
1b39d4b9
LP
2089 bool on_tty;
2090
80876c20
LP
2091 assert(ret);
2092 assert(replies);
2093 assert(text);
2094
1b39d4b9
LP
2095 on_tty = isatty(STDOUT_FILENO);
2096
80876c20
LP
2097 for (;;) {
2098 va_list ap;
2099 char c;
2100 int r;
2101 bool need_nl = true;
2102
1b39d4b9
LP
2103 if (on_tty)
2104 fputs("\x1B[1m", stdout);
b1b2dc0c 2105
80876c20
LP
2106 va_start(ap, text);
2107 vprintf(text, ap);
2108 va_end(ap);
2109
1b39d4b9
LP
2110 if (on_tty)
2111 fputs("\x1B[0m", stdout);
b1b2dc0c 2112
80876c20
LP
2113 fflush(stdout);
2114
2115 if ((r = read_one_char(stdin, &c, &need_nl)) < 0) {
2116
2117 if (r == -EBADMSG) {
2118 puts("Bad input, please try again.");
2119 continue;
2120 }
2121
2122 putchar('\n');
2123 return r;
2124 }
2125
2126 if (need_nl)
2127 putchar('\n');
2128
2129 if (strchr(replies, c)) {
2130 *ret = c;
2131 return 0;
2132 }
2133
2134 puts("Read unexpected character, please try again.");
2135 }
2136}
2137
2138int reset_terminal(int fd) {
2139 struct termios termios;
2140 int r = 0;
3fe5e5d4
LP
2141 long arg;
2142
2143 /* Set terminal to some sane defaults */
80876c20
LP
2144
2145 assert(fd >= 0);
2146
eed1d0e3
LP
2147 /* We leave locked terminal attributes untouched, so that
2148 * Plymouth may set whatever it wants to set, and we don't
2149 * interfere with that. */
3fe5e5d4
LP
2150
2151 /* Disable exclusive mode, just in case */
2152 ioctl(fd, TIOCNXCL);
2153
2154 /* Enable console unicode mode */
2155 arg = K_UNICODE;
2156 ioctl(fd, KDSKBMODE, &arg);
80876c20
LP
2157
2158 if (tcgetattr(fd, &termios) < 0) {
2159 r = -errno;
2160 goto finish;
2161 }
2162
aaf694ca
LP
2163 /* We only reset the stuff that matters to the software. How
2164 * hardware is set up we don't touch assuming that somebody
2165 * else will do that for us */
2166
2167 termios.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | IUCLC);
80876c20
LP
2168 termios.c_iflag |= ICRNL | IMAXBEL | IUTF8;
2169 termios.c_oflag |= ONLCR;
2170 termios.c_cflag |= CREAD;
2171 termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOPRT | ECHOKE;
2172
2173 termios.c_cc[VINTR] = 03; /* ^C */
2174 termios.c_cc[VQUIT] = 034; /* ^\ */
2175 termios.c_cc[VERASE] = 0177;
2176 termios.c_cc[VKILL] = 025; /* ^X */
2177 termios.c_cc[VEOF] = 04; /* ^D */
2178 termios.c_cc[VSTART] = 021; /* ^Q */
2179 termios.c_cc[VSTOP] = 023; /* ^S */
2180 termios.c_cc[VSUSP] = 032; /* ^Z */
2181 termios.c_cc[VLNEXT] = 026; /* ^V */
2182 termios.c_cc[VWERASE] = 027; /* ^W */
2183 termios.c_cc[VREPRINT] = 022; /* ^R */
aaf694ca
LP
2184 termios.c_cc[VEOL] = 0;
2185 termios.c_cc[VEOL2] = 0;
80876c20
LP
2186
2187 termios.c_cc[VTIME] = 0;
2188 termios.c_cc[VMIN] = 1;
2189
2190 if (tcsetattr(fd, TCSANOW, &termios) < 0)
2191 r = -errno;
2192
2193finish:
2194 /* Just in case, flush all crap out */
2195 tcflush(fd, TCIOFLUSH);
2196
2197 return r;
2198}
2199
2200int open_terminal(const char *name, int mode) {
2201 int fd, r;
f73f76ac 2202 unsigned c = 0;
80876c20 2203
f73f76ac
LP
2204 /*
2205 * If a TTY is in the process of being closed opening it might
2206 * cause EIO. This is horribly awful, but unlikely to be
2207 * changed in the kernel. Hence we work around this problem by
2208 * retrying a couple of times.
2209 *
2210 * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245
2211 */
2212
2213 for (;;) {
2214 if ((fd = open(name, mode)) >= 0)
2215 break;
2216
2217 if (errno != EIO)
2218 return -errno;
2219
2220 if (c >= 20)
2221 return -errno;
2222
2223 usleep(50 * USEC_PER_MSEC);
2224 c++;
2225 }
2226
2227 if (fd < 0)
80876c20
LP
2228 return -errno;
2229
2230 if ((r = isatty(fd)) < 0) {
2231 close_nointr_nofail(fd);
2232 return -errno;
2233 }
2234
2235 if (!r) {
2236 close_nointr_nofail(fd);
2237 return -ENOTTY;
2238 }
2239
2240 return fd;
2241}
2242
2243int flush_fd(int fd) {
2244 struct pollfd pollfd;
2245
2246 zero(pollfd);
2247 pollfd.fd = fd;
2248 pollfd.events = POLLIN;
2249
2250 for (;;) {
2251 char buf[1024];
2252 ssize_t l;
2253 int r;
2254
2255 if ((r = poll(&pollfd, 1, 0)) < 0) {
2256
2257 if (errno == EINTR)
2258 continue;
2259
2260 return -errno;
2261 }
2262
2263 if (r == 0)
2264 return 0;
2265
2266 if ((l = read(fd, buf, sizeof(buf))) < 0) {
2267
2268 if (errno == EINTR)
2269 continue;
2270
2271 if (errno == EAGAIN)
2272 return 0;
2273
2274 return -errno;
2275 }
2276
2277 if (l <= 0)
2278 return 0;
2279 }
2280}
2281
21de3988 2282int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocstty_eperm) {
bab45044 2283 int fd = -1, notify = -1, r, wd = -1;
80876c20
LP
2284
2285 assert(name);
2286
2287 /* We use inotify to be notified when the tty is closed. We
2288 * create the watch before checking if we can actually acquire
2289 * it, so that we don't lose any event.
2290 *
2291 * Note: strictly speaking this actually watches for the
2292 * device being closed, it does *not* really watch whether a
2293 * tty loses its controlling process. However, unless some
2294 * rogue process uses TIOCNOTTY on /dev/tty *after* closing
2295 * its tty otherwise this will not become a problem. As long
2296 * as the administrator makes sure not configure any service
2297 * on the same tty as an untrusted user this should not be a
2298 * problem. (Which he probably should not do anyway.) */
2299
2300 if (!fail && !force) {
2301 if ((notify = inotify_init1(IN_CLOEXEC)) < 0) {
2302 r = -errno;
2303 goto fail;
2304 }
2305
2306 if ((wd = inotify_add_watch(notify, name, IN_CLOSE)) < 0) {
2307 r = -errno;
2308 goto fail;
2309 }
2310 }
2311
2312 for (;;) {
e3d1855b
LP
2313 if (notify >= 0)
2314 if ((r = flush_fd(notify)) < 0)
2315 goto fail;
80876c20
LP
2316
2317 /* We pass here O_NOCTTY only so that we can check the return
2318 * value TIOCSCTTY and have a reliable way to figure out if we
2319 * successfully became the controlling process of the tty */
2320 if ((fd = open_terminal(name, O_RDWR|O_NOCTTY)) < 0)
2321 return -errno;
2322
2323 /* First, try to get the tty */
21de3988
LP
2324 r = ioctl(fd, TIOCSCTTY, force);
2325
2326 /* Sometimes it makes sense to ignore TIOCSCTTY
2327 * returning EPERM, i.e. when very likely we already
2328 * are have this controlling terminal. */
2329 if (r < 0 && errno == EPERM && ignore_tiocstty_eperm)
2330 r = 0;
2331
2332 if (r < 0 && (force || fail || errno != EPERM)) {
80876c20
LP
2333 r = -errno;
2334 goto fail;
2335 }
2336
2337 if (r >= 0)
2338 break;
2339
2340 assert(!fail);
2341 assert(!force);
2342 assert(notify >= 0);
2343
2344 for (;;) {
f601daa7 2345 uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX];
80876c20 2346 ssize_t l;
f601daa7 2347 struct inotify_event *e;
80876c20 2348
f601daa7 2349 if ((l = read(notify, &inotify_buffer, sizeof(inotify_buffer))) < 0) {
80876c20 2350
f601daa7
LP
2351 if (errno == EINTR)
2352 continue;
2353
2354 r = -errno;
2355 goto fail;
2356 }
2357
2358 e = (struct inotify_event*) inotify_buffer;
80876c20 2359
f601daa7
LP
2360 while (l > 0) {
2361 size_t step;
80876c20 2362
f601daa7 2363 if (e->wd != wd || !(e->mask & IN_CLOSE)) {
80876c20 2364 r = -EIO;
f601daa7
LP
2365 goto fail;
2366 }
80876c20 2367
f601daa7
LP
2368 step = sizeof(struct inotify_event) + e->len;
2369 assert(step <= (size_t) l);
80876c20 2370
f601daa7
LP
2371 e = (struct inotify_event*) ((uint8_t*) e + step);
2372 l -= step;
80876c20
LP
2373 }
2374
2375 break;
2376 }
2377
2378 /* We close the tty fd here since if the old session
2379 * ended our handle will be dead. It's important that
2380 * we do this after sleeping, so that we don't enter
2381 * an endless loop. */
2382 close_nointr_nofail(fd);
2383 }
2384
2385 if (notify >= 0)
a16e1123 2386 close_nointr_nofail(notify);
80876c20
LP
2387
2388 if ((r = reset_terminal(fd)) < 0)
2389 log_warning("Failed to reset terminal: %s", strerror(-r));
2390
2391 return fd;
2392
2393fail:
2394 if (fd >= 0)
a16e1123 2395 close_nointr_nofail(fd);
80876c20
LP
2396
2397 if (notify >= 0)
a16e1123 2398 close_nointr_nofail(notify);
80876c20
LP
2399
2400 return r;
2401}
2402
2403int release_terminal(void) {
2404 int r = 0, fd;
57cd2192 2405 struct sigaction sa_old, sa_new;
80876c20 2406
57cd2192 2407 if ((fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY)) < 0)
80876c20
LP
2408 return -errno;
2409
57cd2192
LP
2410 /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
2411 * by our own TIOCNOTTY */
2412
2413 zero(sa_new);
2414 sa_new.sa_handler = SIG_IGN;
2415 sa_new.sa_flags = SA_RESTART;
2416 assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
2417
80876c20
LP
2418 if (ioctl(fd, TIOCNOTTY) < 0)
2419 r = -errno;
2420
57cd2192
LP
2421 assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
2422
80876c20
LP
2423 close_nointr_nofail(fd);
2424 return r;
2425}
2426
9a34ec5f
LP
2427int sigaction_many(const struct sigaction *sa, ...) {
2428 va_list ap;
2429 int r = 0, sig;
2430
2431 va_start(ap, sa);
2432 while ((sig = va_arg(ap, int)) > 0)
2433 if (sigaction(sig, sa, NULL) < 0)
2434 r = -errno;
2435 va_end(ap);
2436
2437 return r;
2438}
2439
2440int ignore_signals(int sig, ...) {
a337c6fc 2441 struct sigaction sa;
9a34ec5f
LP
2442 va_list ap;
2443 int r = 0;
a337c6fc
LP
2444
2445 zero(sa);
2446 sa.sa_handler = SIG_IGN;
2447 sa.sa_flags = SA_RESTART;
2448
9a34ec5f
LP
2449 if (sigaction(sig, &sa, NULL) < 0)
2450 r = -errno;
2451
2452 va_start(ap, sig);
2453 while ((sig = va_arg(ap, int)) > 0)
2454 if (sigaction(sig, &sa, NULL) < 0)
2455 r = -errno;
2456 va_end(ap);
2457
2458 return r;
2459}
2460
2461int default_signals(int sig, ...) {
2462 struct sigaction sa;
2463 va_list ap;
2464 int r = 0;
2465
2466 zero(sa);
2467 sa.sa_handler = SIG_DFL;
2468 sa.sa_flags = SA_RESTART;
2469
2470 if (sigaction(sig, &sa, NULL) < 0)
2471 r = -errno;
2472
2473 va_start(ap, sig);
2474 while ((sig = va_arg(ap, int)) > 0)
2475 if (sigaction(sig, &sa, NULL) < 0)
2476 r = -errno;
2477 va_end(ap);
2478
2479 return r;
a337c6fc
LP
2480}
2481
8d567588
LP
2482int close_pipe(int p[]) {
2483 int a = 0, b = 0;
2484
2485 assert(p);
2486
2487 if (p[0] >= 0) {
2488 a = close_nointr(p[0]);
2489 p[0] = -1;
2490 }
2491
2492 if (p[1] >= 0) {
2493 b = close_nointr(p[1]);
2494 p[1] = -1;
2495 }
2496
2497 return a < 0 ? a : b;
2498}
2499
eb22ac37 2500ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
8d567588
LP
2501 uint8_t *p;
2502 ssize_t n = 0;
2503
2504 assert(fd >= 0);
2505 assert(buf);
2506
2507 p = buf;
2508
2509 while (nbytes > 0) {
2510 ssize_t k;
2511
2512 if ((k = read(fd, p, nbytes)) <= 0) {
2513
eb22ac37 2514 if (k < 0 && errno == EINTR)
8d567588
LP
2515 continue;
2516
eb22ac37 2517 if (k < 0 && errno == EAGAIN && do_poll) {
8d567588
LP
2518 struct pollfd pollfd;
2519
2520 zero(pollfd);
2521 pollfd.fd = fd;
2522 pollfd.events = POLLIN;
2523
2524 if (poll(&pollfd, 1, -1) < 0) {
2525 if (errno == EINTR)
2526 continue;
2527
2528 return n > 0 ? n : -errno;
2529 }
2530
2531 if (pollfd.revents != POLLIN)
2532 return n > 0 ? n : -EIO;
2533
2534 continue;
2535 }
2536
2537 return n > 0 ? n : (k < 0 ? -errno : 0);
2538 }
2539
2540 p += k;
2541 nbytes -= k;
2542 n += k;
2543 }
2544
2545 return n;
2546}
2547
eb22ac37
LP
2548ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
2549 const uint8_t *p;
2550 ssize_t n = 0;
2551
2552 assert(fd >= 0);
2553 assert(buf);
2554
2555 p = buf;
2556
2557 while (nbytes > 0) {
2558 ssize_t k;
2559
2560 if ((k = write(fd, p, nbytes)) <= 0) {
2561
2562 if (k < 0 && errno == EINTR)
2563 continue;
2564
2565 if (k < 0 && errno == EAGAIN && do_poll) {
2566 struct pollfd pollfd;
2567
2568 zero(pollfd);
2569 pollfd.fd = fd;
2570 pollfd.events = POLLOUT;
2571
2572 if (poll(&pollfd, 1, -1) < 0) {
2573 if (errno == EINTR)
2574 continue;
2575
2576 return n > 0 ? n : -errno;
2577 }
2578
2579 if (pollfd.revents != POLLOUT)
2580 return n > 0 ? n : -EIO;
2581
2582 continue;
2583 }
2584
2585 return n > 0 ? n : (k < 0 ? -errno : 0);
2586 }
2587
2588 p += k;
2589 nbytes -= k;
2590 n += k;
2591 }
2592
2593 return n;
2594}
2595
8d567588
LP
2596int path_is_mount_point(const char *t) {
2597 struct stat a, b;
35d2e7ec
LP
2598 char *parent;
2599 int r;
8d567588
LP
2600
2601 if (lstat(t, &a) < 0) {
8d567588
LP
2602 if (errno == ENOENT)
2603 return 0;
2604
2605 return -errno;
2606 }
2607
35d2e7ec
LP
2608 if ((r = parent_of_path(t, &parent)) < 0)
2609 return r;
8d567588 2610
35d2e7ec
LP
2611 r = lstat(parent, &b);
2612 free(parent);
8d567588 2613
35d2e7ec
LP
2614 if (r < 0)
2615 return -errno;
8d567588
LP
2616
2617 return a.st_dev != b.st_dev;
2618}
2619
24a6e4a4
LP
2620int parse_usec(const char *t, usec_t *usec) {
2621 static const struct {
2622 const char *suffix;
2623 usec_t usec;
2624 } table[] = {
2625 { "sec", USEC_PER_SEC },
2626 { "s", USEC_PER_SEC },
2627 { "min", USEC_PER_MINUTE },
2628 { "hr", USEC_PER_HOUR },
2629 { "h", USEC_PER_HOUR },
2630 { "d", USEC_PER_DAY },
2631 { "w", USEC_PER_WEEK },
2632 { "msec", USEC_PER_MSEC },
2633 { "ms", USEC_PER_MSEC },
2634 { "m", USEC_PER_MINUTE },
2635 { "usec", 1ULL },
2636 { "us", 1ULL },
2637 { "", USEC_PER_SEC },
2638 };
2639
2640 const char *p;
2641 usec_t r = 0;
2642
2643 assert(t);
2644 assert(usec);
2645
2646 p = t;
2647 do {
2648 long long l;
2649 char *e;
2650 unsigned i;
2651
2652 errno = 0;
2653 l = strtoll(p, &e, 10);
2654
2655 if (errno != 0)
2656 return -errno;
2657
2658 if (l < 0)
2659 return -ERANGE;
2660
2661 if (e == p)
2662 return -EINVAL;
2663
2664 e += strspn(e, WHITESPACE);
2665
2666 for (i = 0; i < ELEMENTSOF(table); i++)
2667 if (startswith(e, table[i].suffix)) {
2668 r += (usec_t) l * table[i].usec;
2669 p = e + strlen(table[i].suffix);
2670 break;
2671 }
2672
2673 if (i >= ELEMENTSOF(table))
2674 return -EINVAL;
2675
2676 } while (*p != 0);
2677
2678 *usec = r;
2679
2680 return 0;
2681}
2682
843d2643
LP
2683int make_stdio(int fd) {
2684 int r, s, t;
2685
2686 assert(fd >= 0);
2687
2688 r = dup2(fd, STDIN_FILENO);
2689 s = dup2(fd, STDOUT_FILENO);
2690 t = dup2(fd, STDERR_FILENO);
2691
2692 if (fd >= 3)
2693 close_nointr_nofail(fd);
2694
2695 if (r < 0 || s < 0 || t < 0)
2696 return -errno;
2697
2698 return 0;
2699}
2700
ade509ce
LP
2701int make_null_stdio(void) {
2702 int null_fd;
2703
2704 if ((null_fd = open("/dev/null", O_RDWR|O_NOCTTY)) < 0)
2705 return -errno;
2706
2707 return make_stdio(null_fd);
2708}
2709
8407a5d0
LP
2710bool is_device_path(const char *path) {
2711
2712 /* Returns true on paths that refer to a device, either in
2713 * sysfs or in /dev */
2714
2715 return
2716 path_startswith(path, "/dev/") ||
2717 path_startswith(path, "/sys/");
2718}
2719
01f78473
LP
2720int dir_is_empty(const char *path) {
2721 DIR *d;
2722 int r;
2723 struct dirent buf, *de;
2724
2725 if (!(d = opendir(path)))
2726 return -errno;
2727
2728 for (;;) {
2729 if ((r = readdir_r(d, &buf, &de)) > 0) {
2730 r = -r;
2731 break;
2732 }
2733
2734 if (!de) {
2735 r = 1;
2736 break;
2737 }
2738
2739 if (!ignore_file(de->d_name)) {
2740 r = 0;
2741 break;
2742 }
2743 }
2744
2745 closedir(d);
2746 return r;
2747}
2748
d3782d60
LP
2749unsigned long long random_ull(void) {
2750 int fd;
2751 uint64_t ull;
2752 ssize_t r;
2753
2754 if ((fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY)) < 0)
2755 goto fallback;
2756
eb22ac37 2757 r = loop_read(fd, &ull, sizeof(ull), true);
d3782d60
LP
2758 close_nointr_nofail(fd);
2759
2760 if (r != sizeof(ull))
2761 goto fallback;
2762
2763 return ull;
2764
2765fallback:
2766 return random() * RAND_MAX + random();
2767}
2768
5b6319dc
LP
2769void rename_process(const char name[8]) {
2770 assert(name);
2771
2772 prctl(PR_SET_NAME, name);
2773
2774 /* This is a like a poor man's setproctitle(). The string
2775 * passed should fit in 7 chars (i.e. the length of
2776 * "systemd") */
2777
2778 if (program_invocation_name)
2779 strncpy(program_invocation_name, name, strlen(program_invocation_name));
2780}
2781
7d793605
LP
2782void sigset_add_many(sigset_t *ss, ...) {
2783 va_list ap;
2784 int sig;
2785
2786 assert(ss);
2787
2788 va_start(ap, ss);
2789 while ((sig = va_arg(ap, int)) > 0)
2790 assert_se(sigaddset(ss, sig) == 0);
2791 va_end(ap);
2792}
2793
ef2f1067
LP
2794char* gethostname_malloc(void) {
2795 struct utsname u;
2796
2797 assert_se(uname(&u) >= 0);
2798
2799 if (u.nodename[0])
2800 return strdup(u.nodename);
2801
2802 return strdup(u.sysname);
2803}
2804
2805char* getlogname_malloc(void) {
2806 uid_t uid;
2807 long bufsize;
2808 char *buf, *name;
2809 struct passwd pwbuf, *pw = NULL;
2810 struct stat st;
2811
2812 if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0)
2813 uid = st.st_uid;
2814 else
2815 uid = getuid();
2816
2817 /* Shortcut things to avoid NSS lookups */
2818 if (uid == 0)
2819 return strdup("root");
2820
2821 if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) <= 0)
2822 bufsize = 4096;
2823
2824 if (!(buf = malloc(bufsize)))
2825 return NULL;
2826
2827 if (getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0 && pw) {
2828 name = strdup(pw->pw_name);
2829 free(buf);
2830 return name;
2831 }
2832
2833 free(buf);
2834
2835 if (asprintf(&name, "%lu", (unsigned long) uid) < 0)
2836 return NULL;
2837
2838 return name;
2839}
2840
fc116c6a
LP
2841int getttyname_malloc(int fd, char **r) {
2842 char path[PATH_MAX], *c;
618e02c7 2843 int k;
8c6db833
LP
2844
2845 assert(r);
ef2f1067 2846
fc116c6a 2847 if ((k = ttyname_r(fd, path, sizeof(path))) != 0)
618e02c7 2848 return -k;
ef2f1067
LP
2849
2850 char_array_0(path);
2851
fc116c6a 2852 if (!(c = strdup(startswith(path, "/dev/") ? path + 5 : path)))
8c6db833
LP
2853 return -ENOMEM;
2854
2855 *r = c;
2856 return 0;
2857}
2858
fc116c6a
LP
2859int getttyname_harder(int fd, char **r) {
2860 int k;
2861 char *s;
2862
2863 if ((k = getttyname_malloc(fd, &s)) < 0)
2864 return k;
2865
2866 if (streq(s, "tty")) {
2867 free(s);
46824d0e 2868 return get_ctty(r, NULL);
fc116c6a
LP
2869 }
2870
2871 *r = s;
2872 return 0;
2873}
2874
2875int get_ctty_devnr(dev_t *d) {
2876 int k;
2877 char line[256], *p;
2878 unsigned long ttynr;
2879 FILE *f;
2880
2881 if (!(f = fopen("/proc/self/stat", "r")))
2882 return -errno;
2883
2884 if (!(fgets(line, sizeof(line), f))) {
2885 k = -errno;
2886 fclose(f);
2887 return k;
2888 }
2889
2890 fclose(f);
2891
2892 if (!(p = strrchr(line, ')')))
2893 return -EIO;
2894
2895 p++;
2896
2897 if (sscanf(p, " "
2898 "%*c " /* state */
2899 "%*d " /* ppid */
2900 "%*d " /* pgrp */
2901 "%*d " /* session */
2902 "%lu ", /* ttynr */
2903 &ttynr) != 1)
2904 return -EIO;
2905
2906 *d = (dev_t) ttynr;
2907 return 0;
2908}
2909
46824d0e 2910int get_ctty(char **r, dev_t *_devnr) {
fc116c6a
LP
2911 int k;
2912 char fn[128], *s, *b, *p;
2913 dev_t devnr;
2914
2915 assert(r);
2916
2917 if ((k = get_ctty_devnr(&devnr)) < 0)
2918 return k;
2919
2920 snprintf(fn, sizeof(fn), "/dev/char/%u:%u", major(devnr), minor(devnr));
2921 char_array_0(fn);
2922
2923 if ((k = readlink_malloc(fn, &s)) < 0) {
2924
2925 if (k != -ENOENT)
2926 return k;
2927
46824d0e
LP
2928 /* This is an ugly hack */
2929 if (major(devnr) == 136) {
2930 if (asprintf(&b, "pts/%lu", (unsigned long) minor(devnr)) < 0)
2931 return -ENOMEM;
2932
2933 *r = b;
2934 if (_devnr)
2935 *_devnr = devnr;
2936
2937 return 0;
2938 }
2939
fc116c6a
LP
2940 /* Probably something like the ptys which have no
2941 * symlink in /dev/char. Let's return something
2942 * vaguely useful. */
2943
2944 if (!(b = strdup(fn + 5)))
2945 return -ENOMEM;
2946
2947 *r = b;
46824d0e
LP
2948 if (_devnr)
2949 *_devnr = devnr;
2950
fc116c6a
LP
2951 return 0;
2952 }
2953
2954 if (startswith(s, "/dev/"))
2955 p = s + 5;
2956 else if (startswith(s, "../"))
2957 p = s + 3;
2958 else
2959 p = s;
2960
2961 b = strdup(p);
2962 free(s);
2963
2964 if (!b)
2965 return -ENOMEM;
2966
2967 *r = b;
46824d0e
LP
2968 if (_devnr)
2969 *_devnr = devnr;
2970
fc116c6a
LP
2971 return 0;
2972}
2973
8c6db833
LP
2974static int rm_rf_children(int fd, bool only_dirs) {
2975 DIR *d;
2976 int ret = 0;
2977
2978 assert(fd >= 0);
2979
2980 /* This returns the first error we run into, but nevertheless
2981 * tries to go on */
2982
2983 if (!(d = fdopendir(fd))) {
2984 close_nointr_nofail(fd);
4c633005
LP
2985
2986 return errno == ENOENT ? 0 : -errno;
8c6db833
LP
2987 }
2988
2989 for (;;) {
2990 struct dirent buf, *de;
2991 bool is_dir;
2992 int r;
2993
2994 if ((r = readdir_r(d, &buf, &de)) != 0) {
2995 if (ret == 0)
2996 ret = -r;
2997 break;
2998 }
2999
3000 if (!de)
3001 break;
3002
3003 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
3004 continue;
3005
3006 if (de->d_type == DT_UNKNOWN) {
3007 struct stat st;
3008
3009 if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
4c633005 3010 if (ret == 0 && errno != ENOENT)
8c6db833
LP
3011 ret = -errno;
3012 continue;
3013 }
3014
3015 is_dir = S_ISDIR(st.st_mode);
3016 } else
3017 is_dir = de->d_type == DT_DIR;
3018
3019 if (is_dir) {
3020 int subdir_fd;
3021
3022 if ((subdir_fd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)) < 0) {
4c633005 3023 if (ret == 0 && errno != ENOENT)
8c6db833
LP
3024 ret = -errno;
3025 continue;
3026 }
3027
3028 if ((r = rm_rf_children(subdir_fd, only_dirs)) < 0) {
3029 if (ret == 0)
3030 ret = r;
3031 }
3032
3033 if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
4c633005 3034 if (ret == 0 && errno != ENOENT)
8c6db833
LP
3035 ret = -errno;
3036 }
3037 } else if (!only_dirs) {
3038
3039 if (unlinkat(fd, de->d_name, 0) < 0) {
4c633005 3040 if (ret == 0 && errno != ENOENT)
8c6db833
LP
3041 ret = -errno;
3042 }
3043 }
3044 }
3045
3046 closedir(d);
3047
3048 return ret;
3049}
3050
3051int rm_rf(const char *path, bool only_dirs, bool delete_root) {
3052 int fd;
3053 int r;
3054
3055 assert(path);
3056
3057 if ((fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)) < 0) {
3058
3059 if (errno != ENOTDIR)
3060 return -errno;
3061
3062 if (delete_root && !only_dirs)
3063 if (unlink(path) < 0)
3064 return -errno;
3065
3066 return 0;
3067 }
3068
3069 r = rm_rf_children(fd, only_dirs);
3070
3071 if (delete_root)
3072 if (rmdir(path) < 0) {
3073 if (r == 0)
3074 r = -errno;
3075 }
3076
3077 return r;
3078}
3079
3080int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
3081 assert(path);
3082
3083 /* Under the assumption that we are running privileged we
3084 * first change the access mode and only then hand out
3085 * ownership to avoid a window where access is too open. */
3086
3087 if (chmod(path, mode) < 0)
3088 return -errno;
3089
3090 if (chown(path, uid, gid) < 0)
3091 return -errno;
3092
3093 return 0;
ef2f1067
LP
3094}
3095
82c121a4
LP
3096cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
3097 cpu_set_t *r;
3098 unsigned n = 1024;
3099
3100 /* Allocates the cpuset in the right size */
3101
3102 for (;;) {
3103 if (!(r = CPU_ALLOC(n)))
3104 return NULL;
3105
3106 if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), r) >= 0) {
3107 CPU_ZERO_S(CPU_ALLOC_SIZE(n), r);
3108
3109 if (ncpus)
3110 *ncpus = n;
3111
3112 return r;
3113 }
3114
3115 CPU_FREE(r);
3116
3117 if (errno != EINVAL)
3118 return NULL;
3119
3120 n *= 2;
3121 }
3122}
3123
9e58ff9c
LP
3124void status_vprintf(const char *format, va_list ap) {
3125 char *s = NULL;
3126 int fd = -1;
3127
3128 assert(format);
3129
3130 /* This independent of logging, as status messages are
3131 * optional and go exclusively to the console. */
3132
3133 if (vasprintf(&s, format, ap) < 0)
3134 goto finish;
3135
3136 if ((fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0)
3137 goto finish;
3138
3139 write(fd, s, strlen(s));
3140
3141finish:
3142 free(s);
3143
3144 if (fd >= 0)
3145 close_nointr_nofail(fd);
3146}
3147
c846ff47
LP
3148void status_printf(const char *format, ...) {
3149 va_list ap;
3150
3151 assert(format);
3152
3153 va_start(ap, format);
3154 status_vprintf(format, ap);
3155 va_end(ap);
3156}
3157
3158void status_welcome(void) {
10aa7034
LP
3159 char *pretty_name = NULL, *ansi_color = NULL;
3160 const char *const_pretty = NULL, *const_color = NULL;
3161 int r;
c846ff47 3162
10aa7034
LP
3163 if ((r = parse_env_file("/etc/os-release", NEWLINE,
3164 "PRETTY_NAME", &pretty_name,
3165 "ANSI_COLOR", &ansi_color,
3166 NULL)) < 0) {
c846ff47 3167
10aa7034
LP
3168 if (r != -ENOENT)
3169 log_warning("Failed to read /etc/os-release: %s", strerror(-r));
3170 }
c846ff47 3171
10aa7034
LP
3172#if defined(TARGET_FEDORA)
3173 if (!pretty_name) {
3174 if ((r = read_one_line_file("/etc/system-release", &pretty_name)) < 0) {
c846ff47 3175
10aa7034
LP
3176 if (r != -ENOENT)
3177 log_warning("Failed to read /etc/system-release: %s", strerror(-r));
3178 } else
3179 truncate_nl(pretty_name);
3180 }
c846ff47 3181
10aa7034 3182 if (!ansi_color && pretty_name) {
c846ff47 3183
10aa7034
LP
3184 /* This tries to mimic the color magic the old Red Hat sysinit
3185 * script did. */
3186
3187 if (startswith(pretty_name, "Red Hat"))
3188 const_color = "0;31"; /* Red for RHEL */
3189 else if (startswith(pretty_name, "Fedora"))
3190 const_color = "0;34"; /* Blue for Fedora */
3191 }
c846ff47
LP
3192
3193#elif defined(TARGET_SUSE)
c846ff47 3194
10aa7034
LP
3195 if (!pretty_name) {
3196 if ((r = read_one_line_file("/etc/SuSE-release", &pretty_name)) < 0) {
c846ff47 3197
10aa7034
LP
3198 if (r != -ENOENT)
3199 log_warning("Failed to read /etc/SuSE-release: %s", strerror(-r));
3200 } else
3201 truncate_nl(pretty_name);
3202 }
c846ff47 3203
10aa7034
LP
3204 if (!ansi_color)
3205 const_color = "0;32"; /* Green for openSUSE */
5a6225fd 3206
0d37b36b 3207#elif defined(TARGET_GENTOO)
0d37b36b 3208
10aa7034
LP
3209 if (!pretty_name) {
3210 if ((r = read_one_line_file("/etc/gentoo-release", &pretty_name)) < 0) {
0d37b36b 3211
10aa7034
LP
3212 if (r != -ENOENT)
3213 log_warning("Failed to read /etc/gentoo-release: %s", strerror(-r));
3214 } else
3215 truncate_nl(pretty_name);
3216 }
0d37b36b 3217
10aa7034
LP
3218 if (!ansi_color)
3219 const_color = "1;34"; /* Light Blue for Gentoo */
5a6225fd 3220
a338bab5
AS
3221#elif defined(TARGET_ALTLINUX)
3222
3223 if (!pretty_name) {
3224 if ((r = read_one_line_file("/etc/altlinux-release", &pretty_name)) < 0) {
3225
3226 if (r != -ENOENT)
3227 log_warning("Failed to read /etc/altlinux-release: %s", strerror(-r));
3228 } else
3229 truncate_nl(pretty_name);
3230 }
3231
3232 if (!ansi_color)
3233 const_color = "0;36"; /* Cyan for ALTLinux */
3234
3235
5a6225fd 3236#elif defined(TARGET_DEBIAN)
5a6225fd 3237
10aa7034 3238 if (!pretty_name) {
22927a36 3239 char *version;
c8bffa43 3240
22927a36 3241 if ((r = read_one_line_file("/etc/debian_version", &version)) < 0) {
5a6225fd 3242
10aa7034
LP
3243 if (r != -ENOENT)
3244 log_warning("Failed to read /etc/debian_version: %s", strerror(-r));
22927a36
MB
3245 } else {
3246 truncate_nl(version);
3247 pretty_name = strappend("Debian ", version);
3248 free(version);
c8bffa43
LP
3249
3250 if (!pretty_name)
3251 log_warning("Failed to allocate Debian version string.");
22927a36 3252 }
10aa7034 3253 }
5a6225fd 3254
10aa7034
LP
3255 if (!ansi_color)
3256 const_color = "1;31"; /* Light Red for Debian */
5a6225fd 3257
274914f9 3258#elif defined(TARGET_UBUNTU)
10aa7034
LP
3259
3260 if ((r = parse_env_file("/etc/lsb-release", NEWLINE,
3261 "DISTRIB_DESCRIPTION", &pretty_name,
3262 NULL)) < 0) {
3263
3264 if (r != -ENOENT)
3265 log_warning("Failed to read /etc/lsb-release: %s", strerror(-r));
3266 }
3267
3268 if (!ansi_color)
3269 const_color = "0;33"; /* Orange/Brown for Ubuntu */
3270
1de4d79b
AB
3271#elif defined(TARGET_MANDRIVA)
3272
3273 if (!pretty_name) {
3274 char *s, *p;
3275
3276 if ((r = read_one_line_file("/etc/mandriva-release", &s) < 0)) {
3277 if (r != -ENOENT)
3278 log_warning("Failed to read /etc/mandriva-release: %s", strerror(-r));
3279 } else {
3280 p = strstr(s, " release ");
3281 if (p) {
3282 *p = '\0';
3283 p += 9;
3284 p[strcspn(p, " ")] = '\0';
3285
3286 /* This corresponds to standard rc.sysinit */
3287 if (asprintf(&pretty_name, "%s\x1B[0;39m %s", s, p) > 0)
3288 const_color = "1;36";
3289 else
3290 log_warning("Failed to allocate Mandriva version string.");
3291 } else
3292 log_warning("Failed to parse /etc/mandriva-release");
3293 free(s);
3294 }
3295 }
3296
c846ff47 3297#endif
10aa7034
LP
3298
3299 if (!pretty_name && !const_pretty)
3300 const_pretty = "Linux";
3301
3302 if (!ansi_color && !const_color)
3303 const_color = "1";
3304
da71f23c 3305 status_printf("\nWelcome to \x1B[%sm%s\x1B[0m!\n\n",
10aa7034
LP
3306 const_color ? const_color : ansi_color,
3307 const_pretty ? const_pretty : pretty_name);
86a3475b
LP
3308
3309 free(ansi_color);
3310 free(pretty_name);
c846ff47
LP
3311}
3312
fab56fc5
LP
3313char *replace_env(const char *format, char **env) {
3314 enum {
3315 WORD,
c24eb49e 3316 CURLY,
fab56fc5
LP
3317 VARIABLE
3318 } state = WORD;
3319
3320 const char *e, *word = format;
3321 char *r = NULL, *k;
3322
3323 assert(format);
3324
3325 for (e = format; *e; e ++) {
3326
3327 switch (state) {
3328
3329 case WORD:
3330 if (*e == '$')
c24eb49e 3331 state = CURLY;
fab56fc5
LP
3332 break;
3333
c24eb49e
LP
3334 case CURLY:
3335 if (*e == '{') {
fab56fc5
LP
3336 if (!(k = strnappend(r, word, e-word-1)))
3337 goto fail;
3338
3339 free(r);
3340 r = k;
3341
3342 word = e-1;
3343 state = VARIABLE;
3344
3345 } else if (*e == '$') {
3346 if (!(k = strnappend(r, word, e-word)))
3347 goto fail;
3348
3349 free(r);
3350 r = k;
3351
3352 word = e+1;
3353 state = WORD;
3354 } else
3355 state = WORD;
3356 break;
3357
3358 case VARIABLE:
c24eb49e 3359 if (*e == '}') {
b95cf362 3360 const char *t;
fab56fc5 3361
b95cf362
LP
3362 if (!(t = strv_env_get_with_length(env, word+2, e-word-2)))
3363 t = "";
fab56fc5 3364
b95cf362
LP
3365 if (!(k = strappend(r, t)))
3366 goto fail;
fab56fc5 3367
b95cf362
LP
3368 free(r);
3369 r = k;
fab56fc5 3370
b95cf362 3371 word = e+1;
fab56fc5
LP
3372 state = WORD;
3373 }
3374 break;
3375 }
3376 }
3377
3378 if (!(k = strnappend(r, word, e-word)))
3379 goto fail;
3380
3381 free(r);
3382 return k;
3383
3384fail:
3385 free(r);
3386 return NULL;
3387}
3388
3389char **replace_env_argv(char **argv, char **env) {
3390 char **r, **i;
c24eb49e
LP
3391 unsigned k = 0, l = 0;
3392
3393 l = strv_length(argv);
fab56fc5 3394
c24eb49e 3395 if (!(r = new(char*, l+1)))
fab56fc5
LP
3396 return NULL;
3397
3398 STRV_FOREACH(i, argv) {
c24eb49e
LP
3399
3400 /* If $FOO appears as single word, replace it by the split up variable */
b95cf362
LP
3401 if ((*i)[0] == '$' && (*i)[1] != '{') {
3402 char *e;
3403 char **w, **m;
3404 unsigned q;
c24eb49e 3405
b95cf362 3406 if ((e = strv_env_get(env, *i+1))) {
c24eb49e
LP
3407
3408 if (!(m = strv_split_quoted(e))) {
3409 r[k] = NULL;
3410 strv_free(r);
3411 return NULL;
3412 }
b95cf362
LP
3413 } else
3414 m = NULL;
c24eb49e 3415
b95cf362
LP
3416 q = strv_length(m);
3417 l = l + q - 1;
c24eb49e 3418
b95cf362
LP
3419 if (!(w = realloc(r, sizeof(char*) * (l+1)))) {
3420 r[k] = NULL;
3421 strv_free(r);
3422 strv_free(m);
3423 return NULL;
3424 }
c24eb49e 3425
b95cf362
LP
3426 r = w;
3427 if (m) {
c24eb49e
LP
3428 memcpy(r + k, m, q * sizeof(char*));
3429 free(m);
c24eb49e 3430 }
b95cf362
LP
3431
3432 k += q;
3433 continue;
c24eb49e
LP
3434 }
3435
3436 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
fab56fc5
LP
3437 if (!(r[k++] = replace_env(*i, env))) {
3438 strv_free(r);
3439 return NULL;
3440 }
3441 }
3442
3443 r[k] = NULL;
3444 return r;
3445}
3446
fa776d8e
LP
3447int columns(void) {
3448 static __thread int parsed_columns = 0;
3449 const char *e;
3450
3451 if (parsed_columns > 0)
3452 return parsed_columns;
3453
3454 if ((e = getenv("COLUMNS")))
3455 parsed_columns = atoi(e);
3456
3457 if (parsed_columns <= 0) {
3458 struct winsize ws;
3459 zero(ws);
3460
9ed95f43 3461 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0)
fa776d8e
LP
3462 parsed_columns = ws.ws_col;
3463 }
3464
3465 if (parsed_columns <= 0)
3466 parsed_columns = 80;
3467
3468 return parsed_columns;
3469}
3470
b4f10a5e
LP
3471int running_in_chroot(void) {
3472 struct stat a, b;
3473
3474 zero(a);
3475 zero(b);
3476
3477 /* Only works as root */
3478
3479 if (stat("/proc/1/root", &a) < 0)
3480 return -errno;
3481
3482 if (stat("/", &b) < 0)
3483 return -errno;
3484
3485 return
3486 a.st_dev != b.st_dev ||
3487 a.st_ino != b.st_ino;
3488}
3489
8fe914ec
LP
3490char *ellipsize(const char *s, unsigned length, unsigned percent) {
3491 size_t l, x;
3492 char *r;
3493
3494 assert(s);
3495 assert(percent <= 100);
3496 assert(length >= 3);
3497
3498 l = strlen(s);
3499
3500 if (l <= 3 || l <= length)
3501 return strdup(s);
3502
3503 if (!(r = new0(char, length+1)))
3504 return r;
3505
3506 x = (length * percent) / 100;
3507
3508 if (x > length - 3)
3509 x = length - 3;
3510
3511 memcpy(r, s, x);
3512 r[x] = '.';
3513 r[x+1] = '.';
3514 r[x+2] = '.';
3515 memcpy(r + x + 3,
3516 s + l - (length - x - 3),
3517 length - x - 3);
3518
3519 return r;
3520}
3521
f6144808
LP
3522int touch(const char *path) {
3523 int fd;
3524
3525 assert(path);
3526
14f3c825 3527 if ((fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0644)) < 0)
f6144808
LP
3528 return -errno;
3529
3530 close_nointr_nofail(fd);
3531 return 0;
3532}
afea26ad 3533
97c4a07d 3534char *unquote(const char *s, const char* quotes) {
11ce3427
LP
3535 size_t l;
3536 assert(s);
3537
3538 if ((l = strlen(s)) < 2)
3539 return strdup(s);
3540
97c4a07d 3541 if (strchr(quotes, s[0]) && s[l-1] == s[0])
11ce3427
LP
3542 return strndup(s+1, l-2);
3543
3544 return strdup(s);
3545}
3546
5f7c426e
LP
3547char *normalize_env_assignment(const char *s) {
3548 char *name, *value, *p, *r;
3549
3550 p = strchr(s, '=');
3551
3552 if (!p) {
3553 if (!(r = strdup(s)))
3554 return NULL;
3555
3556 return strstrip(r);
3557 }
3558
3559 if (!(name = strndup(s, p - s)))
3560 return NULL;
3561
3562 if (!(p = strdup(p+1))) {
3563 free(name);
3564 return NULL;
3565 }
3566
3567 value = unquote(strstrip(p), QUOTES);
3568 free(p);
3569
3570 if (!value) {
3571 free(p);
3572 free(name);
3573 return NULL;
3574 }
3575
3576 if (asprintf(&r, "%s=%s", name, value) < 0)
3577 r = NULL;
3578
3579 free(value);
3580 free(name);
3581
3582 return r;
3583}
3584
8e12a6ae 3585int wait_for_terminate(pid_t pid, siginfo_t *status) {
2e78aa99
LP
3586 assert(pid >= 1);
3587 assert(status);
3588
3589 for (;;) {
8e12a6ae
LP
3590 zero(*status);
3591
3592 if (waitid(P_PID, pid, status, WEXITED) < 0) {
2e78aa99
LP
3593
3594 if (errno == EINTR)
3595 continue;
3596
3597 return -errno;
3598 }
3599
3600 return 0;
3601 }
3602}
3603
97c4a07d
LP
3604int wait_for_terminate_and_warn(const char *name, pid_t pid) {
3605 int r;
3606 siginfo_t status;
3607
3608 assert(name);
3609 assert(pid > 1);
3610
3611 if ((r = wait_for_terminate(pid, &status)) < 0) {
3612 log_warning("Failed to wait for %s: %s", name, strerror(-r));
3613 return r;
3614 }
3615
3616 if (status.si_code == CLD_EXITED) {
3617 if (status.si_status != 0) {
3618 log_warning("%s failed with error code %i.", name, status.si_status);
0a27cf3f 3619 return status.si_status;
97c4a07d
LP
3620 }
3621
3622 log_debug("%s succeeded.", name);
3623 return 0;
3624
3625 } else if (status.si_code == CLD_KILLED ||
3626 status.si_code == CLD_DUMPED) {
3627
3628 log_warning("%s terminated by signal %s.", name, signal_to_string(status.si_status));
3629 return -EPROTO;
3630 }
3631
3632 log_warning("%s failed due to unknown reason.", name);
3633 return -EPROTO;
3634
3635}
3636
3c14d26c 3637void freeze(void) {
720ce21d
LP
3638
3639 /* Make sure nobody waits for us on a socket anymore */
3640 close_all_fds(NULL, 0);
3641
c29597a1
LP
3642 sync();
3643
3c14d26c
LP
3644 for (;;)
3645 pause();
3646}
3647
00dc5d76
LP
3648bool null_or_empty(struct stat *st) {
3649 assert(st);
3650
3651 if (S_ISREG(st->st_mode) && st->st_size <= 0)
3652 return true;
3653
c8f26f42 3654 if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
00dc5d76
LP
3655 return true;
3656
3657 return false;
3658}
3659
a247755d 3660DIR *xopendirat(int fd, const char *name, int flags) {
c4731d11
LP
3661 int nfd;
3662 DIR *d;
3663
3664 if ((nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags)) < 0)
3665 return NULL;
3666
3667 if (!(d = fdopendir(nfd))) {
3668 close_nointr_nofail(nfd);
3669 return NULL;
3670 }
3671
3672 return d;
3b63d2d3
LP
3673}
3674
8a0867d6
LP
3675int signal_from_string_try_harder(const char *s) {
3676 int signo;
3677 assert(s);
3678
3679 if ((signo = signal_from_string(s)) <= 0)
3680 if (startswith(s, "SIG"))
3681 return signal_from_string(s+3);
3682
3683 return signo;
3684}
3685
10717a1a
LP
3686void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
3687
3688 assert(f);
3689 assert(name);
3690 assert(t);
3691
3692 if (!dual_timestamp_is_set(t))
3693 return;
3694
3695 fprintf(f, "%s=%llu %llu\n",
3696 name,
3697 (unsigned long long) t->realtime,
3698 (unsigned long long) t->monotonic);
3699}
3700
799fd0fd 3701void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
10717a1a
LP
3702 unsigned long long a, b;
3703
10717a1a
LP
3704 assert(value);
3705 assert(t);
3706
3707 if (sscanf(value, "%lli %llu", &a, &b) != 2)
3708 log_debug("Failed to parse finish timestamp value %s", value);
3709 else {
3710 t->realtime = a;
3711 t->monotonic = b;
3712 }
3713}
3714
e23a0ce8
LP
3715char *fstab_node_to_udev_node(const char *p) {
3716 char *dn, *t, *u;
3717 int r;
3718
3719 /* FIXME: to follow udev's logic 100% we need to leave valid
3720 * UTF8 chars unescaped */
3721
3722 if (startswith(p, "LABEL=")) {
3723
3724 if (!(u = unquote(p+6, "\"\'")))
3725 return NULL;
3726
3727 t = xescape(u, "/ ");
3728 free(u);
3729
3730 if (!t)
3731 return NULL;
3732
3733 r = asprintf(&dn, "/dev/disk/by-label/%s", t);
3734 free(t);
3735
3736 if (r < 0)
3737 return NULL;
3738
3739 return dn;
3740 }
3741
3742 if (startswith(p, "UUID=")) {
3743
3744 if (!(u = unquote(p+5, "\"\'")))
3745 return NULL;
3746
3747 t = xescape(u, "/ ");
3748 free(u);
3749
3750 if (!t)
3751 return NULL;
3752
0058d7b9 3753 r = asprintf(&dn, "/dev/disk/by-uuid/%s", t);
e23a0ce8
LP
3754 free(t);
3755
3756 if (r < 0)
3757 return NULL;
3758
3759 return dn;
3760 }
3761
3762 return strdup(p);
3763}
3764
e9ddabc2
LP
3765void filter_environ(const char *prefix) {
3766 int i, j;
3767 assert(prefix);
3768
3769 if (!environ)
3770 return;
3771
3772 for (i = 0, j = 0; environ[i]; i++) {
3773
3774 if (startswith(environ[i], prefix))
3775 continue;
3776
3777 environ[j++] = environ[i];
3778 }
3779
3780 environ[j] = NULL;
3781}
3782
f212ac12
LP
3783bool tty_is_vc(const char *tty) {
3784 assert(tty);
3785
3786 if (startswith(tty, "/dev/"))
3787 tty += 5;
3788
3789 return startswith(tty, "tty") &&
3790 tty[3] >= '0' && tty[3] <= '9';
3791}
3792
e3aa71c3 3793const char *default_term_for_tty(const char *tty) {
3030ccd7
LP
3794 char *active = NULL;
3795 const char *term;
3796
e3aa71c3
LP
3797 assert(tty);
3798
3799 if (startswith(tty, "/dev/"))
3800 tty += 5;
3801
3030ccd7
LP
3802 /* Resolve where /dev/console is pointing when determining
3803 * TERM */
3804 if (streq(tty, "console"))
3805 if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) {
3806 truncate_nl(active);
079a09fb
LP
3807
3808 /* If multiple log outputs are configured the
3809 * last one is what /dev/console points to */
3810 if ((tty = strrchr(active, ' ')))
3811 tty++;
3812 else
3813 tty = active;
3030ccd7
LP
3814 }
3815
f212ac12 3816 term = tty_is_vc(tty) ? "TERM=linux" : "TERM=vt100";
3030ccd7 3817 free(active);
e3aa71c3 3818
3030ccd7 3819 return term;
e3aa71c3
LP
3820}
3821
07faed4f
LP
3822/* Returns a short identifier for the various VM implementations */
3823int detect_vm(const char **id) {
46a08e38
LP
3824
3825#if defined(__i386__) || defined(__x86_64__)
3826
3827 /* Both CPUID and DMI are x86 specific interfaces... */
3828
721bca57 3829 static const char *const dmi_vendors[] = {
46a08e38
LP
3830 "/sys/class/dmi/id/sys_vendor",
3831 "/sys/class/dmi/id/board_vendor",
3832 "/sys/class/dmi/id/bios_vendor"
3833 };
3834
4e08da90 3835 static const char dmi_vendor_table[] =
07faed4f
LP
3836 "QEMU\0" "qemu\0"
3837 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
3838 "VMware\0" "vmware\0"
3839 "VMW\0" "vmware\0"
3840 "Microsoft Corporation\0" "microsoft\0"
3841 "innotek GmbH\0" "oracle\0"
3842 "Xen\0" "xen\0"
34df5a34 3843 "Bochs\0" "bochs\0";
07faed4f 3844
4e08da90 3845 static const char cpuid_vendor_table[] =
07faed4f
LP
3846 "XenVMMXenVMM\0" "xen\0"
3847 "KVMKVMKVM\0" "kvm\0"
3848 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
3849 "VMwareVMware\0" "vmware\0"
3850 /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */
34df5a34 3851 "Microsoft Hv\0" "microsoft\0";
07faed4f
LP
3852
3853 uint32_t eax, ecx;
46a08e38
LP
3854 union {
3855 uint32_t sig32[3];
3856 char text[13];
3857 } sig;
46a08e38 3858 unsigned i;
07faed4f 3859 const char *j, *k;
721bca57 3860 bool hypervisor;
46a08e38
LP
3861
3862 /* http://lwn.net/Articles/301888/ */
3863 zero(sig);
3864
46a08e38
LP
3865#if defined (__i386__)
3866#define REG_a "eax"
3867#define REG_b "ebx"
3868#elif defined (__amd64__)
3869#define REG_a "rax"
3870#define REG_b "rbx"
3871#endif
3872
07faed4f
LP
3873 /* First detect whether there is a hypervisor */
3874 eax = 1;
46a08e38
LP
3875 __asm__ __volatile__ (
3876 /* ebx/rbx is being used for PIC! */
3877 " push %%"REG_b" \n\t"
3878 " cpuid \n\t"
46a08e38
LP
3879 " pop %%"REG_b" \n\t"
3880
07faed4f 3881 : "=a" (eax), "=c" (ecx)
46a08e38
LP
3882 : "0" (eax)
3883 );
3884
721bca57
LP
3885 hypervisor = !!(ecx & ecx & 0x80000000U);
3886
3887 if (hypervisor) {
07faed4f
LP
3888
3889 /* There is a hypervisor, see what it is */
3890 eax = 0x40000000U;
3891 __asm__ __volatile__ (
3892 /* ebx/rbx is being used for PIC! */
3893 " push %%"REG_b" \n\t"
3894 " cpuid \n\t"
3895 " mov %%ebx, %1 \n\t"
3896 " pop %%"REG_b" \n\t"
3897
3898 : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2])
3899 : "0" (eax)
3900 );
3901
3902 NULSTR_FOREACH_PAIR(j, k, cpuid_vendor_table)
3903 if (streq(sig.text, j)) {
3904
3905 if (id)
3906 *id = k;
3907
3908 return 1;
3909 }
721bca57 3910 }
07faed4f 3911
721bca57
LP
3912 for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
3913 char *s;
3914 int r;
3915 const char *found = NULL;
3916
3917 if ((r = read_one_line_file(dmi_vendors[i], &s)) < 0) {
3918 if (r != -ENOENT)
3919 return r;
3920
3921 continue;
3922 }
3923
3924 NULSTR_FOREACH_PAIR(j, k, dmi_vendor_table)
3925 if (startswith(s, j))
3926 found = k;
3927 free(s);
3928
3929 if (found) {
3930 if (id)
3931 *id = found;
3932
3933 return 1;
3934 }
3935 }
3936
3937 if (hypervisor) {
07faed4f
LP
3938 if (id)
3939 *id = "other";
3940
3941 return 1;
3942 }
46a08e38 3943
721bca57 3944#endif
07faed4f
LP
3945 return 0;
3946}
3947
ef2df9f4 3948int detect_container(const char **id) {
f9b9232b
LP
3949 FILE *f;
3950
ef2df9f4
LP
3951 /* Unfortunately many of these operations require root access
3952 * in one way or another */
f9b9232b 3953
ef2df9f4
LP
3954 if (geteuid() != 0)
3955 return -EPERM;
3956
3957 if (running_in_chroot() > 0) {
f9b9232b
LP
3958
3959 if (id)
ef2df9f4 3960 *id = "chroot";
f9b9232b
LP
3961
3962 return 1;
3963 }
07faed4f 3964
ef2df9f4
LP
3965 /* /proc/vz exists in container and outside of the container,
3966 * /proc/bc only outside of the container. */
3967 if (access("/proc/vz", F_OK) >= 0 &&
3968 access("/proc/bc", F_OK) < 0) {
07faed4f 3969
ef2df9f4
LP
3970 if (id)
3971 *id = "openvz";
3972
3973 return 1;
f9b9232b 3974 }
07faed4f 3975
f9b9232b
LP
3976 if ((f = fopen("/proc/self/cgroup", "r"))) {
3977
3978 for (;;) {
3979 char line[LINE_MAX], *p;
3980
3981 if (!fgets(line, sizeof(line), f))
3982 break;
3983
3984 if (!(p = strchr(strstrip(line), ':')))
3985 continue;
3986
3987 if (strncmp(p, ":ns:", 4))
3988 continue;
3989
3990 if (!streq(p, ":ns:/")) {
3991 fclose(f);
3992
ef2df9f4 3993 if (id)
28cf382a 3994 *id = "pidns";
ef2df9f4
LP
3995
3996 return 1;
f9b9232b
LP
3997 }
3998 }
3999
4000 fclose(f);
07faed4f
LP
4001 }
4002
ef2df9f4
LP
4003 return 0;
4004}
4005
4006/* Returns a short identifier for the various VM/container implementations */
4007int detect_virtualization(const char **id) {
4008 static __thread const char *cached_id = NULL;
4009 const char *_id;
4010 int r;
4011
4012 if (cached_id) {
4013
4014 if (cached_id == (const char*) -1)
4015 return 0;
4016
4017 if (id)
4018 *id = cached_id;
4019
4020 return 1;
f9b9232b 4021 }
07faed4f 4022
ef2df9f4
LP
4023 if ((r = detect_container(&_id)) != 0)
4024 goto finish;
4025
f9b9232b 4026 r = detect_vm(&_id);
07faed4f 4027
f9b9232b 4028finish:
ef2df9f4 4029 if (r > 0) {
f9b9232b 4030 cached_id = _id;
07faed4f 4031
ef2df9f4
LP
4032 if (id)
4033 *id = _id;
4034 } else if (r == 0)
4035 cached_id = (const char*) -1;
f9b9232b
LP
4036
4037 return r;
46a08e38
LP
4038}
4039
83cc030f
LP
4040void execute_directory(const char *directory, DIR *d, char *argv[]) {
4041 DIR *_d = NULL;
4042 struct dirent *de;
4043 Hashmap *pids = NULL;
4044
4045 assert(directory);
4046
4047 /* Executes all binaries in a directory in parallel and waits
4048 * until all they all finished. */
4049
4050 if (!d) {
4051 if (!(_d = opendir(directory))) {
4052
4053 if (errno == ENOENT)
4054 return;
4055
4056 log_error("Failed to enumerate directory %s: %m", directory);
4057 return;
4058 }
4059
4060 d = _d;
4061 }
4062
4063 if (!(pids = hashmap_new(trivial_hash_func, trivial_compare_func))) {
4064 log_error("Failed to allocate set.");
4065 goto finish;
4066 }
4067
4068 while ((de = readdir(d))) {
4069 char *path;
4070 pid_t pid;
4071 int k;
4072
4073 if (ignore_file(de->d_name))
4074 continue;
4075
4076 if (de->d_type != DT_REG &&
4077 de->d_type != DT_LNK &&
4078 de->d_type != DT_UNKNOWN)
4079 continue;
4080
4081 if (asprintf(&path, "%s/%s", directory, de->d_name) < 0) {
4082 log_error("Out of memory");
4083 continue;
4084 }
4085
4086 if ((pid = fork()) < 0) {
4087 log_error("Failed to fork: %m");
4088 free(path);
4089 continue;
4090 }
4091
4092 if (pid == 0) {
4093 char *_argv[2];
4094 /* Child */
4095
4096 if (!argv) {
4097 _argv[0] = path;
4098 _argv[1] = NULL;
4099 argv = _argv;
4100 } else
4101 if (!argv[0])
4102 argv[0] = path;
4103
4104 execv(path, argv);
4105
4106 log_error("Failed to execute %s: %m", path);
4107 _exit(EXIT_FAILURE);
4108 }
4109
4110 log_debug("Spawned %s as %lu", path, (unsigned long) pid);
4111
4112 if ((k = hashmap_put(pids, UINT_TO_PTR(pid), path)) < 0) {
4113 log_error("Failed to add PID to set: %s", strerror(-k));
4114 free(path);
4115 }
4116 }
4117
4118 while (!hashmap_isempty(pids)) {
4119 siginfo_t si;
4120 char *path;
4121
4122 zero(si);
4123 if (waitid(P_ALL, 0, &si, WEXITED) < 0) {
4124
4125 if (errno == EINTR)
4126 continue;
4127
4128 log_error("waitid() failed: %m");
4129 goto finish;
4130 }
4131
4132 if ((path = hashmap_remove(pids, UINT_TO_PTR(si.si_pid)))) {
4133 if (!is_clean_exit(si.si_code, si.si_status)) {
4134 if (si.si_code == CLD_EXITED)
4135 log_error("%s exited with exit status %i.", path, si.si_status);
4136 else
4137 log_error("%s terminated by signal %s.", path, signal_to_string(si.si_status));
4138 } else
4139 log_debug("%s exited successfully.", path);
4140
4141 free(path);
4142 }
4143 }
4144
4145finish:
4146 if (_d)
4147 closedir(_d);
4148
4149 if (pids)
4150 hashmap_free_free(pids);
4151}
4152
430c18ed
LP
4153int kill_and_sigcont(pid_t pid, int sig) {
4154 int r;
4155
4156 r = kill(pid, sig) < 0 ? -errno : 0;
4157
4158 if (r >= 0)
4159 kill(pid, SIGCONT);
4160
4161 return r;
4162}
4163
05feefe0
LP
4164bool nulstr_contains(const char*nulstr, const char *needle) {
4165 const char *i;
4166
4167 if (!nulstr)
4168 return false;
4169
4170 NULSTR_FOREACH(i, nulstr)
4171 if (streq(i, needle))
4172 return true;
4173
4174 return false;
4175}
4176
1dccbe19
LP
4177static const char *const ioprio_class_table[] = {
4178 [IOPRIO_CLASS_NONE] = "none",
4179 [IOPRIO_CLASS_RT] = "realtime",
4180 [IOPRIO_CLASS_BE] = "best-effort",
4181 [IOPRIO_CLASS_IDLE] = "idle"
4182};
4183
4184DEFINE_STRING_TABLE_LOOKUP(ioprio_class, int);
4185
4186static const char *const sigchld_code_table[] = {
4187 [CLD_EXITED] = "exited",
4188 [CLD_KILLED] = "killed",
4189 [CLD_DUMPED] = "dumped",
4190 [CLD_TRAPPED] = "trapped",
4191 [CLD_STOPPED] = "stopped",
4192 [CLD_CONTINUED] = "continued",
4193};
4194
4195DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
4196
4197static const char *const log_facility_table[LOG_NFACILITIES] = {
4198 [LOG_FAC(LOG_KERN)] = "kern",
4199 [LOG_FAC(LOG_USER)] = "user",
4200 [LOG_FAC(LOG_MAIL)] = "mail",
4201 [LOG_FAC(LOG_DAEMON)] = "daemon",
4202 [LOG_FAC(LOG_AUTH)] = "auth",
4203 [LOG_FAC(LOG_SYSLOG)] = "syslog",
4204 [LOG_FAC(LOG_LPR)] = "lpr",
4205 [LOG_FAC(LOG_NEWS)] = "news",
4206 [LOG_FAC(LOG_UUCP)] = "uucp",
4207 [LOG_FAC(LOG_CRON)] = "cron",
4208 [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
4209 [LOG_FAC(LOG_FTP)] = "ftp",
4210 [LOG_FAC(LOG_LOCAL0)] = "local0",
4211 [LOG_FAC(LOG_LOCAL1)] = "local1",
4212 [LOG_FAC(LOG_LOCAL2)] = "local2",
4213 [LOG_FAC(LOG_LOCAL3)] = "local3",
4214 [LOG_FAC(LOG_LOCAL4)] = "local4",
4215 [LOG_FAC(LOG_LOCAL5)] = "local5",
4216 [LOG_FAC(LOG_LOCAL6)] = "local6",
4217 [LOG_FAC(LOG_LOCAL7)] = "local7"
4218};
4219
4220DEFINE_STRING_TABLE_LOOKUP(log_facility, int);
4221
4222static const char *const log_level_table[] = {
4223 [LOG_EMERG] = "emerg",
4224 [LOG_ALERT] = "alert",
4225 [LOG_CRIT] = "crit",
4226 [LOG_ERR] = "err",
4227 [LOG_WARNING] = "warning",
4228 [LOG_NOTICE] = "notice",
4229 [LOG_INFO] = "info",
4230 [LOG_DEBUG] = "debug"
4231};
4232
4233DEFINE_STRING_TABLE_LOOKUP(log_level, int);
4234
4235static const char* const sched_policy_table[] = {
4236 [SCHED_OTHER] = "other",
4237 [SCHED_BATCH] = "batch",
4238 [SCHED_IDLE] = "idle",
4239 [SCHED_FIFO] = "fifo",
4240 [SCHED_RR] = "rr"
4241};
4242
4243DEFINE_STRING_TABLE_LOOKUP(sched_policy, int);
4244
4245static const char* const rlimit_table[] = {
4246 [RLIMIT_CPU] = "LimitCPU",
4247 [RLIMIT_FSIZE] = "LimitFSIZE",
4248 [RLIMIT_DATA] = "LimitDATA",
4249 [RLIMIT_STACK] = "LimitSTACK",
4250 [RLIMIT_CORE] = "LimitCORE",
4251 [RLIMIT_RSS] = "LimitRSS",
4252 [RLIMIT_NOFILE] = "LimitNOFILE",
4253 [RLIMIT_AS] = "LimitAS",
4254 [RLIMIT_NPROC] = "LimitNPROC",
4255 [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
4256 [RLIMIT_LOCKS] = "LimitLOCKS",
4257 [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
4258 [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
4259 [RLIMIT_NICE] = "LimitNICE",
4260 [RLIMIT_RTPRIO] = "LimitRTPRIO",
4261 [RLIMIT_RTTIME] = "LimitRTTIME"
4262};
4263
4264DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
4fd5948e
LP
4265
4266static const char* const ip_tos_table[] = {
4267 [IPTOS_LOWDELAY] = "low-delay",
4268 [IPTOS_THROUGHPUT] = "throughput",
4269 [IPTOS_RELIABILITY] = "reliability",
4270 [IPTOS_LOWCOST] = "low-cost",
4271};
4272
4273DEFINE_STRING_TABLE_LOOKUP(ip_tos, int);
2e22afe9
LP
4274
4275static const char *const signal_table[] = {
4276 [SIGHUP] = "HUP",
4277 [SIGINT] = "INT",
4278 [SIGQUIT] = "QUIT",
4279 [SIGILL] = "ILL",
4280 [SIGTRAP] = "TRAP",
4281 [SIGABRT] = "ABRT",
4282 [SIGBUS] = "BUS",
4283 [SIGFPE] = "FPE",
4284 [SIGKILL] = "KILL",
4285 [SIGUSR1] = "USR1",
4286 [SIGSEGV] = "SEGV",
4287 [SIGUSR2] = "USR2",
4288 [SIGPIPE] = "PIPE",
4289 [SIGALRM] = "ALRM",
4290 [SIGTERM] = "TERM",
f26ee0b9
LP
4291#ifdef SIGSTKFLT
4292 [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */
4293#endif
2e22afe9
LP
4294 [SIGCHLD] = "CHLD",
4295 [SIGCONT] = "CONT",
4296 [SIGSTOP] = "STOP",
4297 [SIGTSTP] = "TSTP",
4298 [SIGTTIN] = "TTIN",
4299 [SIGTTOU] = "TTOU",
4300 [SIGURG] = "URG",
4301 [SIGXCPU] = "XCPU",
4302 [SIGXFSZ] = "XFSZ",
4303 [SIGVTALRM] = "VTALRM",
4304 [SIGPROF] = "PROF",
4305 [SIGWINCH] = "WINCH",
4306 [SIGIO] = "IO",
4307 [SIGPWR] = "PWR",
4308 [SIGSYS] = "SYS"
4309};
4310
4311DEFINE_STRING_TABLE_LOOKUP(signal, int);