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