]> git.ipfire.org Git - people/ms/systemd.git/blame - util.c
device: allow easy identification of network interfaces without their full sysfs...
[people/ms/systemd.git] / util.c
CommitLineData
60918275
LP
1/*-*- Mode: C; c-basic-offset: 8 -*-*/
2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
60918275
LP
22#include <assert.h>
23#include <string.h>
24#include <unistd.h>
25#include <errno.h>
85261803 26#include <stdlib.h>
034c6ed7
LP
27#include <signal.h>
28#include <stdio.h>
1dccbe19
LP
29#include <syslog.h>
30#include <sched.h>
31#include <sys/resource.h>
ef886c6a 32#include <linux/sched.h>
a9f5d454
LP
33#include <sys/types.h>
34#include <sys/stat.h>
3a0ecb08 35#include <fcntl.h>
a0d40ac5 36#include <dirent.h>
601f6a1e
LP
37#include <sys/ioctl.h>
38#include <linux/vt.h>
39#include <linux/tiocl.h>
80876c20
LP
40#include <termios.h>
41#include <stdarg.h>
42#include <sys/inotify.h>
43#include <sys/poll.h>
8d567588 44#include <libgen.h>
3177a7fa 45#include <ctype.h>
60918275
LP
46
47#include "macro.h"
48#include "util.h"
1dccbe19
LP
49#include "ioprio.h"
50#include "missing.h"
a9f5d454 51#include "log.h"
65d2ebdc 52#include "strv.h"
60918275 53
e05797fb
LP
54bool streq_ptr(const char *a, const char *b) {
55
56 /* Like streq(), but tries to make sense of NULL pointers */
57
58 if (a && b)
59 return streq(a, b);
60
61 if (!a && !b)
62 return true;
63
64 return false;
65}
66
47be870b 67usec_t now(clockid_t clock_id) {
60918275
LP
68 struct timespec ts;
69
47be870b 70 assert_se(clock_gettime(clock_id, &ts) == 0);
60918275
LP
71
72 return timespec_load(&ts);
73}
74
75usec_t timespec_load(const struct timespec *ts) {
76 assert(ts);
77
78 return
79 (usec_t) ts->tv_sec * USEC_PER_SEC +
80 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
81}
82
83struct timespec *timespec_store(struct timespec *ts, usec_t u) {
84 assert(ts);
85
86 ts->tv_sec = (time_t) (u / USEC_PER_SEC);
87 ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
88
89 return ts;
90}
91
92usec_t timeval_load(const struct timeval *tv) {
93 assert(tv);
94
95 return
96 (usec_t) tv->tv_sec * USEC_PER_SEC +
97 (usec_t) tv->tv_usec;
98}
99
100struct timeval *timeval_store(struct timeval *tv, usec_t u) {
101 assert(tv);
102
103 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
104 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
105
106 return tv;
107}
108
109bool endswith(const char *s, const char *postfix) {
110 size_t sl, pl;
111
112 assert(s);
113 assert(postfix);
114
115 sl = strlen(s);
116 pl = strlen(postfix);
117
d4d0d4db
LP
118 if (pl == 0)
119 return true;
120
60918275
LP
121 if (sl < pl)
122 return false;
123
124 return memcmp(s + sl - pl, postfix, pl) == 0;
125}
126
127bool startswith(const char *s, const char *prefix) {
128 size_t sl, pl;
129
130 assert(s);
131 assert(prefix);
132
133 sl = strlen(s);
134 pl = strlen(prefix);
135
d4d0d4db
LP
136 if (pl == 0)
137 return true;
138
60918275
LP
139 if (sl < pl)
140 return false;
141
142 return memcmp(s, prefix, pl) == 0;
143}
144
3177a7fa
MAP
145bool startswith_no_case(const char *s, const char *prefix) {
146 size_t sl, pl;
147 unsigned i;
148
149 assert(s);
150 assert(prefix);
151
152 sl = strlen(s);
153 pl = strlen(prefix);
154
155 if (pl == 0)
156 return true;
157
158 if (sl < pl)
159 return false;
160
161 for(i = 0; i < pl; ++i) {
162 if (tolower(s[i]) != tolower(prefix[i]))
163 return false;
164 }
165
166 return true;
167}
168
79d6d816
LP
169bool first_word(const char *s, const char *word) {
170 size_t sl, wl;
171
172 assert(s);
173 assert(word);
174
175 sl = strlen(s);
176 wl = strlen(word);
177
178 if (sl < wl)
179 return false;
180
d4d0d4db
LP
181 if (wl == 0)
182 return true;
183
79d6d816
LP
184 if (memcmp(s, word, wl) != 0)
185 return false;
186
d4d0d4db
LP
187 return s[wl] == 0 ||
188 strchr(WHITESPACE, s[wl]);
79d6d816
LP
189}
190
42f4e3c4 191int close_nointr(int fd) {
60918275
LP
192 assert(fd >= 0);
193
194 for (;;) {
195 int r;
196
197 if ((r = close(fd)) >= 0)
198 return r;
199
200 if (errno != EINTR)
201 return r;
202 }
203}
85261803 204
85f136b5 205void close_nointr_nofail(int fd) {
80876c20 206 int saved_errno = errno;
85f136b5
LP
207
208 /* like close_nointr() but cannot fail, and guarantees errno
209 * is unchanged */
210
211 assert_se(close_nointr(fd) == 0);
80876c20
LP
212
213 errno = saved_errno;
85f136b5
LP
214}
215
85261803
LP
216int parse_boolean(const char *v) {
217 assert(v);
218
44d8db9e 219 if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
85261803 220 return 1;
44d8db9e 221 else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
85261803
LP
222 return 0;
223
224 return -EINVAL;
225}
226
227int safe_atou(const char *s, unsigned *ret_u) {
228 char *x = NULL;
034c6ed7 229 unsigned long l;
85261803
LP
230
231 assert(s);
232 assert(ret_u);
233
234 errno = 0;
235 l = strtoul(s, &x, 0);
236
237 if (!x || *x || errno)
238 return errno ? -errno : -EINVAL;
239
034c6ed7 240 if ((unsigned long) (unsigned) l != l)
85261803
LP
241 return -ERANGE;
242
243 *ret_u = (unsigned) l;
244 return 0;
245}
246
247int safe_atoi(const char *s, int *ret_i) {
248 char *x = NULL;
034c6ed7 249 long l;
85261803
LP
250
251 assert(s);
252 assert(ret_i);
253
254 errno = 0;
255 l = strtol(s, &x, 0);
256
257 if (!x || *x || errno)
258 return errno ? -errno : -EINVAL;
259
034c6ed7 260 if ((long) (int) l != l)
85261803
LP
261 return -ERANGE;
262
034c6ed7
LP
263 *ret_i = (int) l;
264 return 0;
265}
266
267int safe_atolu(const char *s, long unsigned *ret_lu) {
268 char *x = NULL;
269 unsigned long l;
270
271 assert(s);
272 assert(ret_lu);
273
274 errno = 0;
275 l = strtoul(s, &x, 0);
276
277 if (!x || *x || errno)
278 return errno ? -errno : -EINVAL;
279
280 *ret_lu = l;
281 return 0;
282}
283
284int safe_atoli(const char *s, long int *ret_li) {
285 char *x = NULL;
286 long l;
287
288 assert(s);
289 assert(ret_li);
290
291 errno = 0;
292 l = strtol(s, &x, 0);
293
294 if (!x || *x || errno)
295 return errno ? -errno : -EINVAL;
296
297 *ret_li = l;
298 return 0;
299}
300
301int safe_atollu(const char *s, long long unsigned *ret_llu) {
302 char *x = NULL;
303 unsigned long long l;
304
305 assert(s);
306 assert(ret_llu);
307
308 errno = 0;
309 l = strtoull(s, &x, 0);
310
311 if (!x || *x || errno)
312 return errno ? -errno : -EINVAL;
313
314 *ret_llu = l;
315 return 0;
316}
317
318int safe_atolli(const char *s, long long int *ret_lli) {
319 char *x = NULL;
320 long long l;
321
322 assert(s);
323 assert(ret_lli);
324
325 errno = 0;
326 l = strtoll(s, &x, 0);
327
328 if (!x || *x || errno)
329 return errno ? -errno : -EINVAL;
330
331 *ret_lli = l;
85261803
LP
332 return 0;
333}
a41e8209 334
a41e8209 335/* Split a string into words. */
65d2ebdc 336char *split(const char *c, size_t *l, const char *separator, char **state) {
a41e8209
LP
337 char *current;
338
339 current = *state ? *state : (char*) c;
340
341 if (!*current || *c == 0)
342 return NULL;
343
65d2ebdc
LP
344 current += strspn(current, separator);
345 *l = strcspn(current, separator);
82919e3d
LP
346 *state = current+*l;
347
348 return (char*) current;
349}
350
034c6ed7
LP
351/* Split a string into words, but consider strings enclosed in '' and
352 * "" as words even if they include spaces. */
353char *split_quoted(const char *c, size_t *l, char **state) {
354 char *current;
355
356 current = *state ? *state : (char*) c;
357
358 if (!*current || *c == 0)
359 return NULL;
360
361 current += strspn(current, WHITESPACE);
362
363 if (*current == '\'') {
364 current ++;
365 *l = strcspn(current, "'");
366 *state = current+*l;
367
368 if (**state == '\'')
369 (*state)++;
370 } else if (*current == '\"') {
371 current ++;
b858b600 372 *l = strcspn(current, "\"");
034c6ed7
LP
373 *state = current+*l;
374
375 if (**state == '\"')
376 (*state)++;
377 } else {
378 *l = strcspn(current, WHITESPACE);
379 *state = current+*l;
380 }
381
44d8db9e
LP
382 /* FIXME: Cannot deal with strings that have spaces AND ticks
383 * in them */
384
034c6ed7
LP
385 return (char*) current;
386}
387
65d2ebdc
LP
388char **split_path_and_make_absolute(const char *p) {
389 char **l;
390 assert(p);
391
392 if (!(l = strv_split(p, ":")))
393 return NULL;
394
395 if (!strv_path_make_absolute_cwd(l)) {
396 strv_free(l);
397 return NULL;
398 }
399
400 return l;
401}
402
034c6ed7
LP
403int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
404 int r;
405 FILE *f;
406 char fn[132], line[256], *p;
407 long long unsigned ppid;
408
409 assert(pid >= 0);
410 assert(_ppid);
411
412 assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%llu/stat", (unsigned long long) pid) < (int) (sizeof(fn)-1));
413 fn[sizeof(fn)-1] = 0;
414
415 if (!(f = fopen(fn, "r")))
416 return -errno;
417
418 if (!(fgets(line, sizeof(line), f))) {
419 r = -errno;
420 fclose(f);
421 return r;
422 }
423
424 fclose(f);
425
426 /* Let's skip the pid and comm fields. The latter is enclosed
427 * in () but does not escape any () in its value, so let's
428 * skip over it manually */
429
430 if (!(p = strrchr(line, ')')))
431 return -EIO;
432
433 p++;
434
435 if (sscanf(p, " "
436 "%*c " /* state */
437 "%llu ", /* ppid */
438 &ppid) != 1)
439 return -EIO;
440
441 if ((long long unsigned) (pid_t) ppid != ppid)
442 return -ERANGE;
443
444 *_ppid = (pid_t) ppid;
445
446 return 0;
447}
448
449int write_one_line_file(const char *fn, const char *line) {
450 FILE *f;
451 int r;
452
453 assert(fn);
454 assert(line);
455
456 if (!(f = fopen(fn, "we")))
457 return -errno;
458
459 if (fputs(line, f) < 0) {
460 r = -errno;
461 goto finish;
462 }
463
464 r = 0;
465finish:
466 fclose(f);
467 return r;
468}
469
470int read_one_line_file(const char *fn, char **line) {
471 FILE *f;
472 int r;
11316633 473 char t[2048], *c;
034c6ed7
LP
474
475 assert(fn);
476 assert(line);
477
478 if (!(f = fopen(fn, "re")))
479 return -errno;
480
481 if (!(fgets(t, sizeof(t), f))) {
482 r = -errno;
483 goto finish;
484 }
485
486 if (!(c = strdup(t))) {
487 r = -ENOMEM;
488 goto finish;
489 }
490
491 *line = c;
492 r = 0;
493
494finish:
495 fclose(f);
496 return r;
497}
44d8db9e 498
7072ced8
LP
499char *truncate_nl(char *s) {
500 assert(s);
501
502 s[strcspn(s, NEWLINE)] = 0;
503 return s;
504}
505
506int get_process_name(pid_t pid, char **name) {
507 char *p;
508 int r;
509
510 assert(pid >= 1);
511 assert(name);
512
513 if (asprintf(&p, "/proc/%llu/comm", (unsigned long long) pid) < 0)
514 return -ENOMEM;
515
516 r = read_one_line_file(p, name);
517 free(p);
518
519 if (r < 0)
520 return r;
521
522 truncate_nl(*name);
523 return 0;
524}
525
44d8db9e
LP
526char *strappend(const char *s, const char *suffix) {
527 size_t a, b;
528 char *r;
529
530 assert(s);
531 assert(suffix);
532
533 a = strlen(s);
534 b = strlen(suffix);
535
536 if (!(r = new(char, a+b+1)))
537 return NULL;
538
539 memcpy(r, s, a);
540 memcpy(r+a, suffix, b);
541 r[a+b] = 0;
542
543 return r;
544}
87f0e418
LP
545
546int readlink_malloc(const char *p, char **r) {
547 size_t l = 100;
548
549 assert(p);
550 assert(r);
551
552 for (;;) {
553 char *c;
554 ssize_t n;
555
556 if (!(c = new(char, l)))
557 return -ENOMEM;
558
559 if ((n = readlink(p, c, l-1)) < 0) {
560 int ret = -errno;
561 free(c);
562 return ret;
563 }
564
565 if ((size_t) n < l-1) {
566 c[n] = 0;
567 *r = c;
568 return 0;
569 }
570
571 free(c);
572 l *= 2;
573 }
574}
575
576char *file_name_from_path(const char *p) {
577 char *r;
578
579 assert(p);
580
581 if ((r = strrchr(p, '/')))
582 return r + 1;
583
584 return (char*) p;
585}
0301abf4
LP
586
587bool path_is_absolute(const char *p) {
588 assert(p);
589
590 return p[0] == '/';
591}
592
593bool is_path(const char *p) {
594
595 return !!strchr(p, '/');
596}
597
598char *path_make_absolute(const char *p, const char *prefix) {
599 char *r;
600
601 assert(p);
602
65d2ebdc
LP
603 /* Makes every item in the list an absolute path by prepending
604 * the prefix, if specified and necessary */
605
0301abf4
LP
606 if (path_is_absolute(p) || !prefix)
607 return strdup(p);
608
609 if (asprintf(&r, "%s/%s", prefix, p) < 0)
610 return NULL;
611
612 return r;
613}
2a987ee8 614
65d2ebdc
LP
615char *path_make_absolute_cwd(const char *p) {
616 char *cwd, *r;
617
618 assert(p);
619
620 /* Similar to path_make_absolute(), but prefixes with the
621 * current working directory. */
622
623 if (path_is_absolute(p))
624 return strdup(p);
625
626 if (!(cwd = get_current_dir_name()))
627 return NULL;
628
629 r = path_make_absolute(p, cwd);
630 free(cwd);
631
632 return r;
633}
634
635char **strv_path_make_absolute_cwd(char **l) {
636 char **s;
637
638 /* Goes through every item in the string list and makes it
639 * absolute. This works in place and won't rollback any
640 * changes on failure. */
641
642 STRV_FOREACH(s, l) {
643 char *t;
644
645 if (!(t = path_make_absolute_cwd(*s)))
646 return NULL;
647
648 free(*s);
649 *s = t;
650 }
651
652 return l;
653}
654
2a987ee8
LP
655int reset_all_signal_handlers(void) {
656 int sig;
657
658 for (sig = 1; sig < _NSIG; sig++) {
659 struct sigaction sa;
660
661 if (sig == SIGKILL || sig == SIGSTOP)
662 continue;
663
664 zero(sa);
665 sa.sa_handler = SIG_DFL;
431c32bf 666 sa.sa_flags = SA_RESTART;
2a987ee8
LP
667
668 /* On Linux the first two RT signals are reserved by
669 * glibc, and sigaction() will return EINVAL for them. */
670 if ((sigaction(sig, &sa, NULL) < 0))
671 if (errno != EINVAL)
672 return -errno;
673 }
674
8e274523 675 return 0;
2a987ee8 676}
4a72ff34
LP
677
678char *strstrip(char *s) {
679 char *e, *l = NULL;
680
681 /* Drops trailing whitespace. Modifies the string in
682 * place. Returns pointer to first non-space character */
683
684 s += strspn(s, WHITESPACE);
685
686 for (e = s; *e; e++)
687 if (!strchr(WHITESPACE, *e))
688 l = e;
689
690 if (l)
691 *(l+1) = 0;
692 else
693 *s = 0;
694
695 return s;
4a72ff34
LP
696}
697
ee9b5e01
LP
698char *delete_chars(char *s, const char *bad) {
699 char *f, *t;
700
701 /* Drops all whitespace, regardless where in the string */
702
703 for (f = s, t = s; *f; f++) {
704 if (strchr(bad, *f))
705 continue;
706
707 *(t++) = *f;
708 }
709
710 *t = 0;
711
712 return s;
713}
714
4a72ff34
LP
715char *file_in_same_dir(const char *path, const char *filename) {
716 char *e, *r;
717 size_t k;
718
719 assert(path);
720 assert(filename);
721
722 /* This removes the last component of path and appends
723 * filename, unless the latter is absolute anyway or the
724 * former isn't */
725
726 if (path_is_absolute(filename))
727 return strdup(filename);
728
729 if (!(e = strrchr(path, '/')))
730 return strdup(filename);
731
732 k = strlen(filename);
733 if (!(r = new(char, e-path+1+k+1)))
734 return NULL;
735
736 memcpy(r, path, e-path+1);
737 memcpy(r+(e-path)+1, filename, k+1);
738
739 return r;
740}
fb624d04 741
a9f5d454
LP
742int mkdir_parents(const char *path, mode_t mode) {
743 const char *p, *e;
744
745 assert(path);
746
747 /* Creates every parent directory in the path except the last
748 * component. */
749
750 p = path + strspn(path, "/");
751 for (;;) {
752 int r;
753 char *t;
754
755 e = p + strcspn(p, "/");
756 p = e + strspn(e, "/");
757
758 /* Is this the last component? If so, then we're
759 * done */
760 if (*p == 0)
761 return 0;
762
763 if (!(t = strndup(path, e - path)))
764 return -ENOMEM;
765
766 r = mkdir(t, mode);
767
768 free(t);
769
770 if (r < 0 && errno != EEXIST)
771 return -errno;
772 }
773}
774
bbd67135
LP
775int mkdir_p(const char *path, mode_t mode) {
776 int r;
777
778 /* Like mkdir -p */
779
780 if ((r = mkdir_parents(path, mode)) < 0)
781 return r;
782
783 if (mkdir(path, mode) < 0)
784 return -errno;
785
786 return 0;
787}
788
fb624d04
LP
789char hexchar(int x) {
790 static const char table[16] = "0123456789abcdef";
791
792 return table[x & 15];
793}
4fe88d28
LP
794
795int unhexchar(char c) {
796
797 if (c >= '0' && c <= '9')
798 return c - '0';
799
800 if (c >= 'a' && c <= 'f')
ea430986 801 return c - 'a' + 10;
4fe88d28
LP
802
803 if (c >= 'A' && c <= 'F')
ea430986 804 return c - 'A' + 10;
4fe88d28
LP
805
806 return -1;
807}
808
809char octchar(int x) {
810 return '0' + (x & 7);
811}
812
813int unoctchar(char c) {
814
815 if (c >= '0' && c <= '7')
816 return c - '0';
817
818 return -1;
819}
820
5af98f82
LP
821char decchar(int x) {
822 return '0' + (x % 10);
823}
824
825int undecchar(char c) {
826
827 if (c >= '0' && c <= '9')
828 return c - '0';
829
830 return -1;
831}
832
4fe88d28
LP
833char *cescape(const char *s) {
834 char *r, *t;
835 const char *f;
836
837 assert(s);
838
839 /* Does C style string escaping. */
840
841 if (!(r = new(char, strlen(s)*4 + 1)))
842 return NULL;
843
844 for (f = s, t = r; *f; f++)
845
846 switch (*f) {
847
848 case '\a':
849 *(t++) = '\\';
850 *(t++) = 'a';
851 break;
852 case '\b':
853 *(t++) = '\\';
854 *(t++) = 'b';
855 break;
856 case '\f':
857 *(t++) = '\\';
858 *(t++) = 'f';
859 break;
860 case '\n':
861 *(t++) = '\\';
862 *(t++) = 'n';
863 break;
864 case '\r':
865 *(t++) = '\\';
866 *(t++) = 'r';
867 break;
868 case '\t':
869 *(t++) = '\\';
870 *(t++) = 't';
871 break;
872 case '\v':
873 *(t++) = '\\';
874 *(t++) = 'v';
875 break;
876 case '\\':
877 *(t++) = '\\';
878 *(t++) = '\\';
879 break;
880 case '"':
881 *(t++) = '\\';
882 *(t++) = '"';
883 break;
884 case '\'':
885 *(t++) = '\\';
886 *(t++) = '\'';
887 break;
888
889 default:
890 /* For special chars we prefer octal over
891 * hexadecimal encoding, simply because glib's
892 * g_strescape() does the same */
893 if ((*f < ' ') || (*f >= 127)) {
894 *(t++) = '\\';
895 *(t++) = octchar((unsigned char) *f >> 6);
896 *(t++) = octchar((unsigned char) *f >> 3);
897 *(t++) = octchar((unsigned char) *f);
898 } else
899 *(t++) = *f;
900 break;
901 }
902
903 *t = 0;
904
905 return r;
906}
907
908char *cunescape(const char *s) {
909 char *r, *t;
910 const char *f;
911
912 assert(s);
913
914 /* Undoes C style string escaping */
915
916 if (!(r = new(char, strlen(s)+1)))
917 return r;
918
919 for (f = s, t = r; *f; f++) {
920
921 if (*f != '\\') {
922 *(t++) = *f;
923 continue;
924 }
925
926 f++;
927
928 switch (*f) {
929
930 case 'a':
931 *(t++) = '\a';
932 break;
933 case 'b':
934 *(t++) = '\b';
935 break;
936 case 'f':
937 *(t++) = '\f';
938 break;
939 case 'n':
940 *(t++) = '\n';
941 break;
942 case 'r':
943 *(t++) = '\r';
944 break;
945 case 't':
946 *(t++) = '\t';
947 break;
948 case 'v':
949 *(t++) = '\v';
950 break;
951 case '\\':
952 *(t++) = '\\';
953 break;
954 case '"':
955 *(t++) = '"';
956 break;
957 case '\'':
958 *(t++) = '\'';
959 break;
960
961 case 'x': {
962 /* hexadecimal encoding */
963 int a, b;
964
965 if ((a = unhexchar(f[1])) < 0 ||
966 (b = unhexchar(f[2])) < 0) {
967 /* Invalid escape code, let's take it literal then */
968 *(t++) = '\\';
969 *(t++) = 'x';
970 } else {
971 *(t++) = (char) ((a << 4) | b);
972 f += 2;
973 }
974
975 break;
976 }
977
978 case '0':
979 case '1':
980 case '2':
981 case '3':
982 case '4':
983 case '5':
984 case '6':
985 case '7': {
986 /* octal encoding */
987 int a, b, c;
988
989 if ((a = unoctchar(f[0])) < 0 ||
990 (b = unoctchar(f[1])) < 0 ||
991 (c = unoctchar(f[2])) < 0) {
992 /* Invalid escape code, let's take it literal then */
993 *(t++) = '\\';
994 *(t++) = f[0];
995 } else {
996 *(t++) = (char) ((a << 6) | (b << 3) | c);
997 f += 2;
998 }
999
1000 break;
1001 }
1002
1003 case 0:
1004 /* premature end of string.*/
1005 *(t++) = '\\';
1006 goto finish;
1007
1008 default:
1009 /* Invalid escape code, let's take it literal then */
1010 *(t++) = '\\';
1011 *(t++) = 'f';
1012 break;
1013 }
1014 }
1015
1016finish:
1017 *t = 0;
1018 return r;
1019}
1020
1021
1022char *xescape(const char *s, const char *bad) {
1023 char *r, *t;
1024 const char *f;
1025
1026 /* Escapes all chars in bad, in addition to \ and all special
1027 * chars, in \xFF style escaping. May be reversed with
1028 * cunescape. */
1029
1030 if (!(r = new(char, strlen(s)*4+1)))
1031 return NULL;
1032
1033 for (f = s, t = r; *f; f++) {
1034
b866264a
LP
1035 if ((*f < ' ') || (*f >= 127) ||
1036 (*f == '\\') || strchr(bad, *f)) {
4fe88d28
LP
1037 *(t++) = '\\';
1038 *(t++) = 'x';
1039 *(t++) = hexchar(*f >> 4);
1040 *(t++) = hexchar(*f);
1041 } else
1042 *(t++) = *f;
1043 }
1044
1045 *t = 0;
1046
1047 return r;
1048}
1049
ea430986 1050char *bus_path_escape(const char *s) {
ea430986
LP
1051 char *r, *t;
1052 const char *f;
1053
47be870b
LP
1054 assert(s);
1055
ea430986
LP
1056 /* Escapes all chars that D-Bus' object path cannot deal
1057 * with. Can be reverse with bus_path_unescape() */
1058
1059 if (!(r = new(char, strlen(s)*3+1)))
1060 return NULL;
1061
1062 for (f = s, t = r; *f; f++) {
1063
1064 if (!(*f >= 'A' && *f <= 'Z') &&
1065 !(*f >= 'a' && *f <= 'z') &&
1066 !(*f >= '0' && *f <= '9')) {
1067 *(t++) = '_';
1068 *(t++) = hexchar(*f >> 4);
1069 *(t++) = hexchar(*f);
1070 } else
1071 *(t++) = *f;
1072 }
1073
1074 *t = 0;
1075
1076 return r;
1077}
1078
9e2f7c11 1079char *bus_path_unescape(const char *f) {
ea430986 1080 char *r, *t;
ea430986 1081
9e2f7c11 1082 assert(f);
47be870b 1083
9e2f7c11 1084 if (!(r = strdup(f)))
ea430986
LP
1085 return NULL;
1086
9e2f7c11 1087 for (t = r; *f; f++) {
ea430986
LP
1088
1089 if (*f == '_') {
1090 int a, b;
1091
1092 if ((a = unhexchar(f[1])) < 0 ||
1093 (b = unhexchar(f[2])) < 0) {
1094 /* Invalid escape code, let's take it literal then */
1095 *(t++) = '_';
1096 } else {
1097 *(t++) = (char) ((a << 4) | b);
1098 f += 2;
1099 }
1100 } else
1101 *(t++) = *f;
1102 }
1103
1104 *t = 0;
1105
1106 return r;
1107}
1108
4fe88d28
LP
1109char *path_kill_slashes(char *path) {
1110 char *f, *t;
1111 bool slash = false;
1112
1113 /* Removes redundant inner and trailing slashes. Modifies the
1114 * passed string in-place.
1115 *
1116 * ///foo///bar/ becomes /foo/bar
1117 */
1118
1119 for (f = path, t = path; *f; f++) {
1120
1121 if (*f == '/') {
1122 slash = true;
1123 continue;
1124 }
1125
1126 if (slash) {
1127 slash = false;
1128 *(t++) = '/';
1129 }
1130
1131 *(t++) = *f;
1132 }
1133
1134 /* Special rule, if we are talking of the root directory, a
1135 trailing slash is good */
1136
1137 if (t == path && slash)
1138 *(t++) = '/';
1139
1140 *t = 0;
1141 return path;
1142}
1143
1144bool path_startswith(const char *path, const char *prefix) {
1145 assert(path);
1146 assert(prefix);
1147
1148 if ((path[0] == '/') != (prefix[0] == '/'))
1149 return false;
1150
1151 for (;;) {
1152 size_t a, b;
1153
1154 path += strspn(path, "/");
1155 prefix += strspn(prefix, "/");
1156
1157 if (*prefix == 0)
1158 return true;
1159
1160 if (*path == 0)
1161 return false;
1162
1163 a = strcspn(path, "/");
1164 b = strcspn(prefix, "/");
1165
1166 if (a != b)
1167 return false;
1168
1169 if (memcmp(path, prefix, a) != 0)
1170 return false;
1171
1172 path += a;
1173 prefix += b;
1174 }
1175}
1176
15ae422b
LP
1177bool path_equal(const char *a, const char *b) {
1178 assert(a);
1179 assert(b);
1180
1181 if ((a[0] == '/') != (b[0] == '/'))
1182 return false;
1183
1184 for (;;) {
1185 size_t j, k;
1186
1187 a += strspn(a, "/");
1188 b += strspn(b, "/");
1189
1190 if (*a == 0 && *b == 0)
1191 return true;
1192
1193 if (*a == 0 || *b == 0)
1194 return false;
1195
1196 j = strcspn(a, "/");
1197 k = strcspn(b, "/");
1198
1199 if (j != k)
1200 return false;
1201
1202 if (memcmp(a, b, j) != 0)
1203 return false;
1204
1205 a += j;
1206 b += k;
1207 }
1208}
1209
67d51650 1210char *ascii_strlower(char *t) {
4fe88d28
LP
1211 char *p;
1212
67d51650 1213 assert(t);
4fe88d28 1214
67d51650 1215 for (p = t; *p; p++)
4fe88d28
LP
1216 if (*p >= 'A' && *p <= 'Z')
1217 *p = *p - 'A' + 'a';
1218
67d51650 1219 return t;
4fe88d28 1220}
1dccbe19 1221
c85dc17b
LP
1222bool ignore_file(const char *filename) {
1223 assert(filename);
1224
1225 return
1226 filename[0] == '.' ||
6c78be3c 1227 streq(filename, "lost+found") ||
c85dc17b
LP
1228 endswith(filename, "~") ||
1229 endswith(filename, ".rpmnew") ||
1230 endswith(filename, ".rpmsave") ||
1231 endswith(filename, ".rpmorig") ||
1232 endswith(filename, ".dpkg-old") ||
1233 endswith(filename, ".dpkg-new") ||
1234 endswith(filename, ".swp");
1235}
1236
3a0ecb08
LP
1237int fd_nonblock(int fd, bool nonblock) {
1238 int flags;
1239
1240 assert(fd >= 0);
1241
1242 if ((flags = fcntl(fd, F_GETFL, 0)) < 0)
1243 return -errno;
1244
1245 if (nonblock)
1246 flags |= O_NONBLOCK;
1247 else
1248 flags &= ~O_NONBLOCK;
1249
1250 if (fcntl(fd, F_SETFL, flags) < 0)
1251 return -errno;
1252
1253 return 0;
1254}
1255
1256int fd_cloexec(int fd, bool cloexec) {
1257 int flags;
1258
1259 assert(fd >= 0);
1260
1261 if ((flags = fcntl(fd, F_GETFD, 0)) < 0)
1262 return -errno;
1263
1264 if (cloexec)
1265 flags |= FD_CLOEXEC;
1266 else
1267 flags &= ~FD_CLOEXEC;
1268
1269 if (fcntl(fd, F_SETFD, flags) < 0)
1270 return -errno;
1271
1272 return 0;
1273}
1274
a0d40ac5
LP
1275int close_all_fds(const int except[], unsigned n_except) {
1276 DIR *d;
1277 struct dirent *de;
1278 int r = 0;
1279
1280 if (!(d = opendir("/proc/self/fd")))
1281 return -errno;
1282
1283 while ((de = readdir(d))) {
a7610064 1284 int fd = -1;
a0d40ac5 1285
a16e1123 1286 if (ignore_file(de->d_name))
a0d40ac5
LP
1287 continue;
1288
1289 if ((r = safe_atoi(de->d_name, &fd)) < 0)
1290 goto finish;
1291
1292 if (fd < 3)
1293 continue;
1294
1295 if (fd == dirfd(d))
1296 continue;
1297
1298 if (except) {
1299 bool found;
1300 unsigned i;
1301
1302 found = false;
1303 for (i = 0; i < n_except; i++)
1304 if (except[i] == fd) {
1305 found = true;
1306 break;
1307 }
1308
1309 if (found)
1310 continue;
1311 }
1312
2f357920
LP
1313 if ((r = close_nointr(fd)) < 0) {
1314 /* Valgrind has its own FD and doesn't want to have it closed */
1315 if (errno != EBADF)
1316 goto finish;
1317 }
a0d40ac5
LP
1318 }
1319
2f357920
LP
1320 r = 0;
1321
a0d40ac5
LP
1322finish:
1323 closedir(d);
1324 return r;
1325}
1326
db12775d
LP
1327bool chars_intersect(const char *a, const char *b) {
1328 const char *p;
1329
1330 /* Returns true if any of the chars in a are in b. */
1331 for (p = a; *p; p++)
1332 if (strchr(b, *p))
1333 return true;
1334
1335 return false;
1336}
1337
8b6c7120
LP
1338char *format_timestamp(char *buf, size_t l, usec_t t) {
1339 struct tm tm;
1340 time_t sec;
1341
1342 assert(buf);
1343 assert(l > 0);
1344
1345 if (t <= 0)
1346 return NULL;
1347
1348 sec = (time_t) t / USEC_PER_SEC;
1349
1350 if (strftime(buf, l, "%a, %d %b %Y %H:%M:%S %z", localtime_r(&sec, &tm)) <= 0)
1351 return NULL;
1352
1353 return buf;
1354}
1355
42856c10
LP
1356bool fstype_is_network(const char *fstype) {
1357 static const char * const table[] = {
1358 "cifs",
1359 "smbfs",
1360 "ncpfs",
1361 "nfs",
1362 "nfs4"
1363 };
1364
1365 unsigned i;
1366
1367 for (i = 0; i < ELEMENTSOF(table); i++)
1368 if (streq(table[i], fstype))
1369 return true;
1370
1371 return false;
1372}
1373
601f6a1e
LP
1374int chvt(int vt) {
1375 int fd, r = 0;
1376
1377 if ((fd = open("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0)
1378 return -errno;
1379
1380 if (vt < 0) {
1381 int tiocl[2] = {
1382 TIOCL_GETKMSGREDIRECT,
1383 0
1384 };
1385
1386 if (ioctl(fd, TIOCLINUX, tiocl) < 0)
1387 return -errno;
1388
1389 vt = tiocl[0] <= 0 ? 1 : tiocl[0];
1390 }
1391
1392 if (ioctl(fd, VT_ACTIVATE, vt) < 0)
1393 r = -errno;
1394
a16e1123 1395 close_nointr_nofail(r);
601f6a1e
LP
1396 return r;
1397}
1398
80876c20
LP
1399int read_one_char(FILE *f, char *ret, bool *need_nl) {
1400 struct termios old_termios, new_termios;
1401 char c;
1402 char line[1024];
1403
1404 assert(f);
1405 assert(ret);
1406
1407 if (tcgetattr(fileno(f), &old_termios) >= 0) {
1408 new_termios = old_termios;
1409
1410 new_termios.c_lflag &= ~ICANON;
1411 new_termios.c_cc[VMIN] = 1;
1412 new_termios.c_cc[VTIME] = 0;
1413
1414 if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) {
1415 size_t k;
1416
1417 k = fread(&c, 1, 1, f);
1418
1419 tcsetattr(fileno(f), TCSADRAIN, &old_termios);
1420
1421 if (k <= 0)
1422 return -EIO;
1423
1424 if (need_nl)
1425 *need_nl = c != '\n';
1426
1427 *ret = c;
1428 return 0;
1429 }
1430 }
1431
1432 if (!(fgets(line, sizeof(line), f)))
1433 return -EIO;
1434
1435 truncate_nl(line);
1436
1437 if (strlen(line) != 1)
1438 return -EBADMSG;
1439
1440 if (need_nl)
1441 *need_nl = false;
1442
1443 *ret = line[0];
1444 return 0;
1445}
1446
1447int ask(char *ret, const char *replies, const char *text, ...) {
1448 assert(ret);
1449 assert(replies);
1450 assert(text);
1451
1452 for (;;) {
1453 va_list ap;
1454 char c;
1455 int r;
1456 bool need_nl = true;
1457
b1b2dc0c
LP
1458 fputs("\x1B[1m", stdout);
1459
80876c20
LP
1460 va_start(ap, text);
1461 vprintf(text, ap);
1462 va_end(ap);
1463
b1b2dc0c
LP
1464 fputs("\x1B[0m", stdout);
1465
80876c20
LP
1466 fflush(stdout);
1467
1468 if ((r = read_one_char(stdin, &c, &need_nl)) < 0) {
1469
1470 if (r == -EBADMSG) {
1471 puts("Bad input, please try again.");
1472 continue;
1473 }
1474
1475 putchar('\n');
1476 return r;
1477 }
1478
1479 if (need_nl)
1480 putchar('\n');
1481
1482 if (strchr(replies, c)) {
1483 *ret = c;
1484 return 0;
1485 }
1486
1487 puts("Read unexpected character, please try again.");
1488 }
1489}
1490
1491int reset_terminal(int fd) {
1492 struct termios termios;
1493 int r = 0;
1494
1495 assert(fd >= 0);
1496
aaf694ca 1497 /* Set terminal to some sane defaults */
80876c20
LP
1498
1499 if (tcgetattr(fd, &termios) < 0) {
1500 r = -errno;
1501 goto finish;
1502 }
1503
aaf694ca
LP
1504 /* We only reset the stuff that matters to the software. How
1505 * hardware is set up we don't touch assuming that somebody
1506 * else will do that for us */
1507
1508 termios.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | IUCLC);
80876c20
LP
1509 termios.c_iflag |= ICRNL | IMAXBEL | IUTF8;
1510 termios.c_oflag |= ONLCR;
1511 termios.c_cflag |= CREAD;
1512 termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOPRT | ECHOKE;
1513
1514 termios.c_cc[VINTR] = 03; /* ^C */
1515 termios.c_cc[VQUIT] = 034; /* ^\ */
1516 termios.c_cc[VERASE] = 0177;
1517 termios.c_cc[VKILL] = 025; /* ^X */
1518 termios.c_cc[VEOF] = 04; /* ^D */
1519 termios.c_cc[VSTART] = 021; /* ^Q */
1520 termios.c_cc[VSTOP] = 023; /* ^S */
1521 termios.c_cc[VSUSP] = 032; /* ^Z */
1522 termios.c_cc[VLNEXT] = 026; /* ^V */
1523 termios.c_cc[VWERASE] = 027; /* ^W */
1524 termios.c_cc[VREPRINT] = 022; /* ^R */
aaf694ca
LP
1525 termios.c_cc[VEOL] = 0;
1526 termios.c_cc[VEOL2] = 0;
80876c20
LP
1527
1528 termios.c_cc[VTIME] = 0;
1529 termios.c_cc[VMIN] = 1;
1530
1531 if (tcsetattr(fd, TCSANOW, &termios) < 0)
1532 r = -errno;
1533
1534finish:
1535 /* Just in case, flush all crap out */
1536 tcflush(fd, TCIOFLUSH);
1537
1538 return r;
1539}
1540
1541int open_terminal(const char *name, int mode) {
1542 int fd, r;
1543
1544 if ((fd = open(name, mode)) < 0)
1545 return -errno;
1546
1547 if ((r = isatty(fd)) < 0) {
1548 close_nointr_nofail(fd);
1549 return -errno;
1550 }
1551
1552 if (!r) {
1553 close_nointr_nofail(fd);
1554 return -ENOTTY;
1555 }
1556
1557 return fd;
1558}
1559
1560int flush_fd(int fd) {
1561 struct pollfd pollfd;
1562
1563 zero(pollfd);
1564 pollfd.fd = fd;
1565 pollfd.events = POLLIN;
1566
1567 for (;;) {
1568 char buf[1024];
1569 ssize_t l;
1570 int r;
1571
1572 if ((r = poll(&pollfd, 1, 0)) < 0) {
1573
1574 if (errno == EINTR)
1575 continue;
1576
1577 return -errno;
1578 }
1579
1580 if (r == 0)
1581 return 0;
1582
1583 if ((l = read(fd, buf, sizeof(buf))) < 0) {
1584
1585 if (errno == EINTR)
1586 continue;
1587
1588 if (errno == EAGAIN)
1589 return 0;
1590
1591 return -errno;
1592 }
1593
1594 if (l <= 0)
1595 return 0;
1596 }
1597}
1598
1599int acquire_terminal(const char *name, bool fail, bool force) {
bab45044 1600 int fd = -1, notify = -1, r, wd = -1;
80876c20
LP
1601
1602 assert(name);
1603
1604 /* We use inotify to be notified when the tty is closed. We
1605 * create the watch before checking if we can actually acquire
1606 * it, so that we don't lose any event.
1607 *
1608 * Note: strictly speaking this actually watches for the
1609 * device being closed, it does *not* really watch whether a
1610 * tty loses its controlling process. However, unless some
1611 * rogue process uses TIOCNOTTY on /dev/tty *after* closing
1612 * its tty otherwise this will not become a problem. As long
1613 * as the administrator makes sure not configure any service
1614 * on the same tty as an untrusted user this should not be a
1615 * problem. (Which he probably should not do anyway.) */
1616
1617 if (!fail && !force) {
1618 if ((notify = inotify_init1(IN_CLOEXEC)) < 0) {
1619 r = -errno;
1620 goto fail;
1621 }
1622
1623 if ((wd = inotify_add_watch(notify, name, IN_CLOSE)) < 0) {
1624 r = -errno;
1625 goto fail;
1626 }
1627 }
1628
1629 for (;;) {
1630 if ((r = flush_fd(notify)) < 0)
1631 goto fail;
1632
1633 /* We pass here O_NOCTTY only so that we can check the return
1634 * value TIOCSCTTY and have a reliable way to figure out if we
1635 * successfully became the controlling process of the tty */
1636 if ((fd = open_terminal(name, O_RDWR|O_NOCTTY)) < 0)
1637 return -errno;
1638
1639 /* First, try to get the tty */
1640 if ((r = ioctl(fd, TIOCSCTTY, force)) < 0 &&
1641 (force || fail || errno != EPERM)) {
1642 r = -errno;
1643 goto fail;
1644 }
1645
1646 if (r >= 0)
1647 break;
1648
1649 assert(!fail);
1650 assert(!force);
1651 assert(notify >= 0);
1652
1653 for (;;) {
1654 struct inotify_event e;
1655 ssize_t l;
1656
1657 if ((l = read(notify, &e, sizeof(e))) != sizeof(e)) {
1658
1659 if (l < 0) {
1660
1661 if (errno == EINTR)
1662 continue;
1663
1664 r = -errno;
1665 } else
1666 r = -EIO;
1667
1668 goto fail;
1669 }
1670
1671 if (e.wd != wd || !(e.mask & IN_CLOSE)) {
1672 r = -errno;
1673 goto fail;
1674 }
1675
1676 break;
1677 }
1678
1679 /* We close the tty fd here since if the old session
1680 * ended our handle will be dead. It's important that
1681 * we do this after sleeping, so that we don't enter
1682 * an endless loop. */
1683 close_nointr_nofail(fd);
1684 }
1685
1686 if (notify >= 0)
a16e1123 1687 close_nointr_nofail(notify);
80876c20
LP
1688
1689 if ((r = reset_terminal(fd)) < 0)
1690 log_warning("Failed to reset terminal: %s", strerror(-r));
1691
1692 return fd;
1693
1694fail:
1695 if (fd >= 0)
a16e1123 1696 close_nointr_nofail(fd);
80876c20
LP
1697
1698 if (notify >= 0)
a16e1123 1699 close_nointr_nofail(notify);
80876c20
LP
1700
1701 return r;
1702}
1703
1704int release_terminal(void) {
1705 int r = 0, fd;
57cd2192 1706 struct sigaction sa_old, sa_new;
80876c20 1707
57cd2192 1708 if ((fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY)) < 0)
80876c20
LP
1709 return -errno;
1710
57cd2192
LP
1711 /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
1712 * by our own TIOCNOTTY */
1713
1714 zero(sa_new);
1715 sa_new.sa_handler = SIG_IGN;
1716 sa_new.sa_flags = SA_RESTART;
1717 assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
1718
80876c20
LP
1719 if (ioctl(fd, TIOCNOTTY) < 0)
1720 r = -errno;
1721
57cd2192
LP
1722 assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
1723
80876c20
LP
1724 close_nointr_nofail(fd);
1725 return r;
1726}
1727
a337c6fc
LP
1728int ignore_signal(int sig) {
1729 struct sigaction sa;
1730
1731 zero(sa);
1732 sa.sa_handler = SIG_IGN;
1733 sa.sa_flags = SA_RESTART;
1734
1735 return sigaction(sig, &sa, NULL);
1736}
1737
8d567588
LP
1738int close_pipe(int p[]) {
1739 int a = 0, b = 0;
1740
1741 assert(p);
1742
1743 if (p[0] >= 0) {
1744 a = close_nointr(p[0]);
1745 p[0] = -1;
1746 }
1747
1748 if (p[1] >= 0) {
1749 b = close_nointr(p[1]);
1750 p[1] = -1;
1751 }
1752
1753 return a < 0 ? a : b;
1754}
1755
1756ssize_t loop_read(int fd, void *buf, size_t nbytes) {
1757 uint8_t *p;
1758 ssize_t n = 0;
1759
1760 assert(fd >= 0);
1761 assert(buf);
1762
1763 p = buf;
1764
1765 while (nbytes > 0) {
1766 ssize_t k;
1767
1768 if ((k = read(fd, p, nbytes)) <= 0) {
1769
1770 if (errno == EINTR)
1771 continue;
1772
1773 if (errno == EAGAIN) {
1774 struct pollfd pollfd;
1775
1776 zero(pollfd);
1777 pollfd.fd = fd;
1778 pollfd.events = POLLIN;
1779
1780 if (poll(&pollfd, 1, -1) < 0) {
1781 if (errno == EINTR)
1782 continue;
1783
1784 return n > 0 ? n : -errno;
1785 }
1786
1787 if (pollfd.revents != POLLIN)
1788 return n > 0 ? n : -EIO;
1789
1790 continue;
1791 }
1792
1793 return n > 0 ? n : (k < 0 ? -errno : 0);
1794 }
1795
1796 p += k;
1797 nbytes -= k;
1798 n += k;
1799 }
1800
1801 return n;
1802}
1803
1804int path_is_mount_point(const char *t) {
1805 struct stat a, b;
1806 char *copy;
1807
1808 if (lstat(t, &a) < 0) {
1809
1810 if (errno == ENOENT)
1811 return 0;
1812
1813 return -errno;
1814 }
1815
1816 if (!(copy = strdup(t)))
1817 return -ENOMEM;
1818
1819 if (lstat(dirname(copy), &b) < 0) {
1820 free(copy);
1821 return -errno;
1822 }
1823
1824 free(copy);
1825
1826 return a.st_dev != b.st_dev;
1827}
1828
24a6e4a4
LP
1829int parse_usec(const char *t, usec_t *usec) {
1830 static const struct {
1831 const char *suffix;
1832 usec_t usec;
1833 } table[] = {
1834 { "sec", USEC_PER_SEC },
1835 { "s", USEC_PER_SEC },
1836 { "min", USEC_PER_MINUTE },
1837 { "hr", USEC_PER_HOUR },
1838 { "h", USEC_PER_HOUR },
1839 { "d", USEC_PER_DAY },
1840 { "w", USEC_PER_WEEK },
1841 { "msec", USEC_PER_MSEC },
1842 { "ms", USEC_PER_MSEC },
1843 { "m", USEC_PER_MINUTE },
1844 { "usec", 1ULL },
1845 { "us", 1ULL },
1846 { "", USEC_PER_SEC },
1847 };
1848
1849 const char *p;
1850 usec_t r = 0;
1851
1852 assert(t);
1853 assert(usec);
1854
1855 p = t;
1856 do {
1857 long long l;
1858 char *e;
1859 unsigned i;
1860
1861 errno = 0;
1862 l = strtoll(p, &e, 10);
1863
1864 if (errno != 0)
1865 return -errno;
1866
1867 if (l < 0)
1868 return -ERANGE;
1869
1870 if (e == p)
1871 return -EINVAL;
1872
1873 e += strspn(e, WHITESPACE);
1874
1875 for (i = 0; i < ELEMENTSOF(table); i++)
1876 if (startswith(e, table[i].suffix)) {
1877 r += (usec_t) l * table[i].usec;
1878 p = e + strlen(table[i].suffix);
1879 break;
1880 }
1881
1882 if (i >= ELEMENTSOF(table))
1883 return -EINVAL;
1884
1885 } while (*p != 0);
1886
1887 *usec = r;
1888
1889 return 0;
1890}
1891
1dccbe19
LP
1892static const char *const ioprio_class_table[] = {
1893 [IOPRIO_CLASS_NONE] = "none",
1894 [IOPRIO_CLASS_RT] = "realtime",
1895 [IOPRIO_CLASS_BE] = "best-effort",
1896 [IOPRIO_CLASS_IDLE] = "idle"
1897};
1898
1899DEFINE_STRING_TABLE_LOOKUP(ioprio_class, int);
1900
1901static const char *const sigchld_code_table[] = {
1902 [CLD_EXITED] = "exited",
1903 [CLD_KILLED] = "killed",
1904 [CLD_DUMPED] = "dumped",
1905 [CLD_TRAPPED] = "trapped",
1906 [CLD_STOPPED] = "stopped",
1907 [CLD_CONTINUED] = "continued",
1908};
1909
1910DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
1911
1912static const char *const log_facility_table[LOG_NFACILITIES] = {
1913 [LOG_FAC(LOG_KERN)] = "kern",
1914 [LOG_FAC(LOG_USER)] = "user",
1915 [LOG_FAC(LOG_MAIL)] = "mail",
1916 [LOG_FAC(LOG_DAEMON)] = "daemon",
1917 [LOG_FAC(LOG_AUTH)] = "auth",
1918 [LOG_FAC(LOG_SYSLOG)] = "syslog",
1919 [LOG_FAC(LOG_LPR)] = "lpr",
1920 [LOG_FAC(LOG_NEWS)] = "news",
1921 [LOG_FAC(LOG_UUCP)] = "uucp",
1922 [LOG_FAC(LOG_CRON)] = "cron",
1923 [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
1924 [LOG_FAC(LOG_FTP)] = "ftp",
1925 [LOG_FAC(LOG_LOCAL0)] = "local0",
1926 [LOG_FAC(LOG_LOCAL1)] = "local1",
1927 [LOG_FAC(LOG_LOCAL2)] = "local2",
1928 [LOG_FAC(LOG_LOCAL3)] = "local3",
1929 [LOG_FAC(LOG_LOCAL4)] = "local4",
1930 [LOG_FAC(LOG_LOCAL5)] = "local5",
1931 [LOG_FAC(LOG_LOCAL6)] = "local6",
1932 [LOG_FAC(LOG_LOCAL7)] = "local7"
1933};
1934
1935DEFINE_STRING_TABLE_LOOKUP(log_facility, int);
1936
1937static const char *const log_level_table[] = {
1938 [LOG_EMERG] = "emerg",
1939 [LOG_ALERT] = "alert",
1940 [LOG_CRIT] = "crit",
1941 [LOG_ERR] = "err",
1942 [LOG_WARNING] = "warning",
1943 [LOG_NOTICE] = "notice",
1944 [LOG_INFO] = "info",
1945 [LOG_DEBUG] = "debug"
1946};
1947
1948DEFINE_STRING_TABLE_LOOKUP(log_level, int);
1949
1950static const char* const sched_policy_table[] = {
1951 [SCHED_OTHER] = "other",
1952 [SCHED_BATCH] = "batch",
1953 [SCHED_IDLE] = "idle",
1954 [SCHED_FIFO] = "fifo",
1955 [SCHED_RR] = "rr"
1956};
1957
1958DEFINE_STRING_TABLE_LOOKUP(sched_policy, int);
1959
1960static const char* const rlimit_table[] = {
1961 [RLIMIT_CPU] = "LimitCPU",
1962 [RLIMIT_FSIZE] = "LimitFSIZE",
1963 [RLIMIT_DATA] = "LimitDATA",
1964 [RLIMIT_STACK] = "LimitSTACK",
1965 [RLIMIT_CORE] = "LimitCORE",
1966 [RLIMIT_RSS] = "LimitRSS",
1967 [RLIMIT_NOFILE] = "LimitNOFILE",
1968 [RLIMIT_AS] = "LimitAS",
1969 [RLIMIT_NPROC] = "LimitNPROC",
1970 [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
1971 [RLIMIT_LOCKS] = "LimitLOCKS",
1972 [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
1973 [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
1974 [RLIMIT_NICE] = "LimitNICE",
1975 [RLIMIT_RTPRIO] = "LimitRTPRIO",
1976 [RLIMIT_RTTIME] = "LimitRTTIME"
1977};
1978
1979DEFINE_STRING_TABLE_LOOKUP(rlimit, int);