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