]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/util.c
device: make use of new libudev tags logic
[thirdparty/systemd.git] / src / util.c
CommitLineData
60918275
LP
1/*-*- Mode: C; c-basic-offset: 8 -*-*/
2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
60918275
LP
22#include <assert.h>
23#include <string.h>
24#include <unistd.h>
25#include <errno.h>
85261803 26#include <stdlib.h>
034c6ed7
LP
27#include <signal.h>
28#include <stdio.h>
1dccbe19
LP
29#include <syslog.h>
30#include <sched.h>
31#include <sys/resource.h>
ef886c6a 32#include <linux/sched.h>
a9f5d454
LP
33#include <sys/types.h>
34#include <sys/stat.h>
3a0ecb08 35#include <fcntl.h>
a0d40ac5 36#include <dirent.h>
601f6a1e
LP
37#include <sys/ioctl.h>
38#include <linux/vt.h>
39#include <linux/tiocl.h>
80876c20
LP
40#include <termios.h>
41#include <stdarg.h>
42#include <sys/inotify.h>
43#include <sys/poll.h>
8d567588 44#include <libgen.h>
3177a7fa 45#include <ctype.h>
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",
ca139f94
LP
1362 "nfs4",
1363 "gfs",
1364 "gfs2"
42856c10
LP
1365 };
1366
1367 unsigned i;
1368
1369 for (i = 0; i < ELEMENTSOF(table); i++)
1370 if (streq(table[i], fstype))
1371 return true;
1372
1373 return false;
1374}
1375
601f6a1e
LP
1376int chvt(int vt) {
1377 int fd, r = 0;
1378
1379 if ((fd = open("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0)
1380 return -errno;
1381
1382 if (vt < 0) {
1383 int tiocl[2] = {
1384 TIOCL_GETKMSGREDIRECT,
1385 0
1386 };
1387
1388 if (ioctl(fd, TIOCLINUX, tiocl) < 0)
1389 return -errno;
1390
1391 vt = tiocl[0] <= 0 ? 1 : tiocl[0];
1392 }
1393
1394 if (ioctl(fd, VT_ACTIVATE, vt) < 0)
1395 r = -errno;
1396
a16e1123 1397 close_nointr_nofail(r);
601f6a1e
LP
1398 return r;
1399}
1400
80876c20
LP
1401int read_one_char(FILE *f, char *ret, bool *need_nl) {
1402 struct termios old_termios, new_termios;
1403 char c;
1404 char line[1024];
1405
1406 assert(f);
1407 assert(ret);
1408
1409 if (tcgetattr(fileno(f), &old_termios) >= 0) {
1410 new_termios = old_termios;
1411
1412 new_termios.c_lflag &= ~ICANON;
1413 new_termios.c_cc[VMIN] = 1;
1414 new_termios.c_cc[VTIME] = 0;
1415
1416 if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) {
1417 size_t k;
1418
1419 k = fread(&c, 1, 1, f);
1420
1421 tcsetattr(fileno(f), TCSADRAIN, &old_termios);
1422
1423 if (k <= 0)
1424 return -EIO;
1425
1426 if (need_nl)
1427 *need_nl = c != '\n';
1428
1429 *ret = c;
1430 return 0;
1431 }
1432 }
1433
1434 if (!(fgets(line, sizeof(line), f)))
1435 return -EIO;
1436
1437 truncate_nl(line);
1438
1439 if (strlen(line) != 1)
1440 return -EBADMSG;
1441
1442 if (need_nl)
1443 *need_nl = false;
1444
1445 *ret = line[0];
1446 return 0;
1447}
1448
1449int ask(char *ret, const char *replies, const char *text, ...) {
1450 assert(ret);
1451 assert(replies);
1452 assert(text);
1453
1454 for (;;) {
1455 va_list ap;
1456 char c;
1457 int r;
1458 bool need_nl = true;
1459
b1b2dc0c
LP
1460 fputs("\x1B[1m", stdout);
1461
80876c20
LP
1462 va_start(ap, text);
1463 vprintf(text, ap);
1464 va_end(ap);
1465
b1b2dc0c
LP
1466 fputs("\x1B[0m", stdout);
1467
80876c20
LP
1468 fflush(stdout);
1469
1470 if ((r = read_one_char(stdin, &c, &need_nl)) < 0) {
1471
1472 if (r == -EBADMSG) {
1473 puts("Bad input, please try again.");
1474 continue;
1475 }
1476
1477 putchar('\n');
1478 return r;
1479 }
1480
1481 if (need_nl)
1482 putchar('\n');
1483
1484 if (strchr(replies, c)) {
1485 *ret = c;
1486 return 0;
1487 }
1488
1489 puts("Read unexpected character, please try again.");
1490 }
1491}
1492
1493int reset_terminal(int fd) {
1494 struct termios termios;
1495 int r = 0;
1496
1497 assert(fd >= 0);
1498
aaf694ca 1499 /* Set terminal to some sane defaults */
80876c20
LP
1500
1501 if (tcgetattr(fd, &termios) < 0) {
1502 r = -errno;
1503 goto finish;
1504 }
1505
aaf694ca
LP
1506 /* We only reset the stuff that matters to the software. How
1507 * hardware is set up we don't touch assuming that somebody
1508 * else will do that for us */
1509
1510 termios.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | IUCLC);
80876c20
LP
1511 termios.c_iflag |= ICRNL | IMAXBEL | IUTF8;
1512 termios.c_oflag |= ONLCR;
1513 termios.c_cflag |= CREAD;
1514 termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOPRT | ECHOKE;
1515
1516 termios.c_cc[VINTR] = 03; /* ^C */
1517 termios.c_cc[VQUIT] = 034; /* ^\ */
1518 termios.c_cc[VERASE] = 0177;
1519 termios.c_cc[VKILL] = 025; /* ^X */
1520 termios.c_cc[VEOF] = 04; /* ^D */
1521 termios.c_cc[VSTART] = 021; /* ^Q */
1522 termios.c_cc[VSTOP] = 023; /* ^S */
1523 termios.c_cc[VSUSP] = 032; /* ^Z */
1524 termios.c_cc[VLNEXT] = 026; /* ^V */
1525 termios.c_cc[VWERASE] = 027; /* ^W */
1526 termios.c_cc[VREPRINT] = 022; /* ^R */
aaf694ca
LP
1527 termios.c_cc[VEOL] = 0;
1528 termios.c_cc[VEOL2] = 0;
80876c20
LP
1529
1530 termios.c_cc[VTIME] = 0;
1531 termios.c_cc[VMIN] = 1;
1532
1533 if (tcsetattr(fd, TCSANOW, &termios) < 0)
1534 r = -errno;
1535
1536finish:
1537 /* Just in case, flush all crap out */
1538 tcflush(fd, TCIOFLUSH);
1539
1540 return r;
1541}
1542
1543int open_terminal(const char *name, int mode) {
1544 int fd, r;
1545
1546 if ((fd = open(name, mode)) < 0)
1547 return -errno;
1548
1549 if ((r = isatty(fd)) < 0) {
1550 close_nointr_nofail(fd);
1551 return -errno;
1552 }
1553
1554 if (!r) {
1555 close_nointr_nofail(fd);
1556 return -ENOTTY;
1557 }
1558
1559 return fd;
1560}
1561
1562int flush_fd(int fd) {
1563 struct pollfd pollfd;
1564
1565 zero(pollfd);
1566 pollfd.fd = fd;
1567 pollfd.events = POLLIN;
1568
1569 for (;;) {
1570 char buf[1024];
1571 ssize_t l;
1572 int r;
1573
1574 if ((r = poll(&pollfd, 1, 0)) < 0) {
1575
1576 if (errno == EINTR)
1577 continue;
1578
1579 return -errno;
1580 }
1581
1582 if (r == 0)
1583 return 0;
1584
1585 if ((l = read(fd, buf, sizeof(buf))) < 0) {
1586
1587 if (errno == EINTR)
1588 continue;
1589
1590 if (errno == EAGAIN)
1591 return 0;
1592
1593 return -errno;
1594 }
1595
1596 if (l <= 0)
1597 return 0;
1598 }
1599}
1600
21de3988 1601int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocstty_eperm) {
bab45044 1602 int fd = -1, notify = -1, r, wd = -1;
80876c20
LP
1603
1604 assert(name);
1605
1606 /* We use inotify to be notified when the tty is closed. We
1607 * create the watch before checking if we can actually acquire
1608 * it, so that we don't lose any event.
1609 *
1610 * Note: strictly speaking this actually watches for the
1611 * device being closed, it does *not* really watch whether a
1612 * tty loses its controlling process. However, unless some
1613 * rogue process uses TIOCNOTTY on /dev/tty *after* closing
1614 * its tty otherwise this will not become a problem. As long
1615 * as the administrator makes sure not configure any service
1616 * on the same tty as an untrusted user this should not be a
1617 * problem. (Which he probably should not do anyway.) */
1618
1619 if (!fail && !force) {
1620 if ((notify = inotify_init1(IN_CLOEXEC)) < 0) {
1621 r = -errno;
1622 goto fail;
1623 }
1624
1625 if ((wd = inotify_add_watch(notify, name, IN_CLOSE)) < 0) {
1626 r = -errno;
1627 goto fail;
1628 }
1629 }
1630
1631 for (;;) {
e3d1855b
LP
1632 if (notify >= 0)
1633 if ((r = flush_fd(notify)) < 0)
1634 goto fail;
80876c20
LP
1635
1636 /* We pass here O_NOCTTY only so that we can check the return
1637 * value TIOCSCTTY and have a reliable way to figure out if we
1638 * successfully became the controlling process of the tty */
1639 if ((fd = open_terminal(name, O_RDWR|O_NOCTTY)) < 0)
1640 return -errno;
1641
1642 /* First, try to get the tty */
21de3988
LP
1643 r = ioctl(fd, TIOCSCTTY, force);
1644
1645 /* Sometimes it makes sense to ignore TIOCSCTTY
1646 * returning EPERM, i.e. when very likely we already
1647 * are have this controlling terminal. */
1648 if (r < 0 && errno == EPERM && ignore_tiocstty_eperm)
1649 r = 0;
1650
1651 if (r < 0 && (force || fail || errno != EPERM)) {
80876c20
LP
1652 r = -errno;
1653 goto fail;
1654 }
1655
1656 if (r >= 0)
1657 break;
1658
1659 assert(!fail);
1660 assert(!force);
1661 assert(notify >= 0);
1662
1663 for (;;) {
1664 struct inotify_event e;
1665 ssize_t l;
1666
1667 if ((l = read(notify, &e, sizeof(e))) != sizeof(e)) {
1668
1669 if (l < 0) {
1670
1671 if (errno == EINTR)
1672 continue;
1673
1674 r = -errno;
1675 } else
1676 r = -EIO;
1677
1678 goto fail;
1679 }
1680
1681 if (e.wd != wd || !(e.mask & IN_CLOSE)) {
1682 r = -errno;
1683 goto fail;
1684 }
1685
1686 break;
1687 }
1688
1689 /* We close the tty fd here since if the old session
1690 * ended our handle will be dead. It's important that
1691 * we do this after sleeping, so that we don't enter
1692 * an endless loop. */
1693 close_nointr_nofail(fd);
1694 }
1695
1696 if (notify >= 0)
a16e1123 1697 close_nointr_nofail(notify);
80876c20
LP
1698
1699 if ((r = reset_terminal(fd)) < 0)
1700 log_warning("Failed to reset terminal: %s", strerror(-r));
1701
1702 return fd;
1703
1704fail:
1705 if (fd >= 0)
a16e1123 1706 close_nointr_nofail(fd);
80876c20
LP
1707
1708 if (notify >= 0)
a16e1123 1709 close_nointr_nofail(notify);
80876c20
LP
1710
1711 return r;
1712}
1713
1714int release_terminal(void) {
1715 int r = 0, fd;
57cd2192 1716 struct sigaction sa_old, sa_new;
80876c20 1717
57cd2192 1718 if ((fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY)) < 0)
80876c20
LP
1719 return -errno;
1720
57cd2192
LP
1721 /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
1722 * by our own TIOCNOTTY */
1723
1724 zero(sa_new);
1725 sa_new.sa_handler = SIG_IGN;
1726 sa_new.sa_flags = SA_RESTART;
1727 assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
1728
80876c20
LP
1729 if (ioctl(fd, TIOCNOTTY) < 0)
1730 r = -errno;
1731
57cd2192
LP
1732 assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
1733
80876c20
LP
1734 close_nointr_nofail(fd);
1735 return r;
1736}
1737
a337c6fc
LP
1738int ignore_signal(int sig) {
1739 struct sigaction sa;
1740
1741 zero(sa);
1742 sa.sa_handler = SIG_IGN;
1743 sa.sa_flags = SA_RESTART;
1744
1745 return sigaction(sig, &sa, NULL);
1746}
1747
8d567588
LP
1748int close_pipe(int p[]) {
1749 int a = 0, b = 0;
1750
1751 assert(p);
1752
1753 if (p[0] >= 0) {
1754 a = close_nointr(p[0]);
1755 p[0] = -1;
1756 }
1757
1758 if (p[1] >= 0) {
1759 b = close_nointr(p[1]);
1760 p[1] = -1;
1761 }
1762
1763 return a < 0 ? a : b;
1764}
1765
1766ssize_t loop_read(int fd, void *buf, size_t nbytes) {
1767 uint8_t *p;
1768 ssize_t n = 0;
1769
1770 assert(fd >= 0);
1771 assert(buf);
1772
1773 p = buf;
1774
1775 while (nbytes > 0) {
1776 ssize_t k;
1777
1778 if ((k = read(fd, p, nbytes)) <= 0) {
1779
1780 if (errno == EINTR)
1781 continue;
1782
1783 if (errno == EAGAIN) {
1784 struct pollfd pollfd;
1785
1786 zero(pollfd);
1787 pollfd.fd = fd;
1788 pollfd.events = POLLIN;
1789
1790 if (poll(&pollfd, 1, -1) < 0) {
1791 if (errno == EINTR)
1792 continue;
1793
1794 return n > 0 ? n : -errno;
1795 }
1796
1797 if (pollfd.revents != POLLIN)
1798 return n > 0 ? n : -EIO;
1799
1800 continue;
1801 }
1802
1803 return n > 0 ? n : (k < 0 ? -errno : 0);
1804 }
1805
1806 p += k;
1807 nbytes -= k;
1808 n += k;
1809 }
1810
1811 return n;
1812}
1813
1814int path_is_mount_point(const char *t) {
1815 struct stat a, b;
1816 char *copy;
1817
1818 if (lstat(t, &a) < 0) {
1819
1820 if (errno == ENOENT)
1821 return 0;
1822
1823 return -errno;
1824 }
1825
1826 if (!(copy = strdup(t)))
1827 return -ENOMEM;
1828
1829 if (lstat(dirname(copy), &b) < 0) {
1830 free(copy);
1831 return -errno;
1832 }
1833
1834 free(copy);
1835
1836 return a.st_dev != b.st_dev;
1837}
1838
24a6e4a4
LP
1839int parse_usec(const char *t, usec_t *usec) {
1840 static const struct {
1841 const char *suffix;
1842 usec_t usec;
1843 } table[] = {
1844 { "sec", USEC_PER_SEC },
1845 { "s", USEC_PER_SEC },
1846 { "min", USEC_PER_MINUTE },
1847 { "hr", USEC_PER_HOUR },
1848 { "h", USEC_PER_HOUR },
1849 { "d", USEC_PER_DAY },
1850 { "w", USEC_PER_WEEK },
1851 { "msec", USEC_PER_MSEC },
1852 { "ms", USEC_PER_MSEC },
1853 { "m", USEC_PER_MINUTE },
1854 { "usec", 1ULL },
1855 { "us", 1ULL },
1856 { "", USEC_PER_SEC },
1857 };
1858
1859 const char *p;
1860 usec_t r = 0;
1861
1862 assert(t);
1863 assert(usec);
1864
1865 p = t;
1866 do {
1867 long long l;
1868 char *e;
1869 unsigned i;
1870
1871 errno = 0;
1872 l = strtoll(p, &e, 10);
1873
1874 if (errno != 0)
1875 return -errno;
1876
1877 if (l < 0)
1878 return -ERANGE;
1879
1880 if (e == p)
1881 return -EINVAL;
1882
1883 e += strspn(e, WHITESPACE);
1884
1885 for (i = 0; i < ELEMENTSOF(table); i++)
1886 if (startswith(e, table[i].suffix)) {
1887 r += (usec_t) l * table[i].usec;
1888 p = e + strlen(table[i].suffix);
1889 break;
1890 }
1891
1892 if (i >= ELEMENTSOF(table))
1893 return -EINVAL;
1894
1895 } while (*p != 0);
1896
1897 *usec = r;
1898
1899 return 0;
1900}
1901
843d2643
LP
1902int make_stdio(int fd) {
1903 int r, s, t;
1904
1905 assert(fd >= 0);
1906
1907 r = dup2(fd, STDIN_FILENO);
1908 s = dup2(fd, STDOUT_FILENO);
1909 t = dup2(fd, STDERR_FILENO);
1910
1911 if (fd >= 3)
1912 close_nointr_nofail(fd);
1913
1914 if (r < 0 || s < 0 || t < 0)
1915 return -errno;
1916
1917 return 0;
1918}
1919
cb8a8f78
LP
1920bool is_clean_exit(int code, int status) {
1921
1922 if (code == CLD_EXITED)
1923 return status == 0;
1924
1925 /* If a daemon does not implement handlers for some of the
1926 * signals that's not considered an unclean shutdown */
1927 if (code == CLD_KILLED)
1928 return
1929 status == SIGHUP ||
1930 status == SIGINT ||
1931 status == SIGTERM ||
1932 status == SIGPIPE;
1933
1934 return false;
1935}
1936
8407a5d0
LP
1937bool is_device_path(const char *path) {
1938
1939 /* Returns true on paths that refer to a device, either in
1940 * sysfs or in /dev */
1941
1942 return
1943 path_startswith(path, "/dev/") ||
1944 path_startswith(path, "/sys/");
1945}
1946
1dccbe19
LP
1947static const char *const ioprio_class_table[] = {
1948 [IOPRIO_CLASS_NONE] = "none",
1949 [IOPRIO_CLASS_RT] = "realtime",
1950 [IOPRIO_CLASS_BE] = "best-effort",
1951 [IOPRIO_CLASS_IDLE] = "idle"
1952};
1953
1954DEFINE_STRING_TABLE_LOOKUP(ioprio_class, int);
1955
1956static const char *const sigchld_code_table[] = {
1957 [CLD_EXITED] = "exited",
1958 [CLD_KILLED] = "killed",
1959 [CLD_DUMPED] = "dumped",
1960 [CLD_TRAPPED] = "trapped",
1961 [CLD_STOPPED] = "stopped",
1962 [CLD_CONTINUED] = "continued",
1963};
1964
1965DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
1966
1967static const char *const log_facility_table[LOG_NFACILITIES] = {
1968 [LOG_FAC(LOG_KERN)] = "kern",
1969 [LOG_FAC(LOG_USER)] = "user",
1970 [LOG_FAC(LOG_MAIL)] = "mail",
1971 [LOG_FAC(LOG_DAEMON)] = "daemon",
1972 [LOG_FAC(LOG_AUTH)] = "auth",
1973 [LOG_FAC(LOG_SYSLOG)] = "syslog",
1974 [LOG_FAC(LOG_LPR)] = "lpr",
1975 [LOG_FAC(LOG_NEWS)] = "news",
1976 [LOG_FAC(LOG_UUCP)] = "uucp",
1977 [LOG_FAC(LOG_CRON)] = "cron",
1978 [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
1979 [LOG_FAC(LOG_FTP)] = "ftp",
1980 [LOG_FAC(LOG_LOCAL0)] = "local0",
1981 [LOG_FAC(LOG_LOCAL1)] = "local1",
1982 [LOG_FAC(LOG_LOCAL2)] = "local2",
1983 [LOG_FAC(LOG_LOCAL3)] = "local3",
1984 [LOG_FAC(LOG_LOCAL4)] = "local4",
1985 [LOG_FAC(LOG_LOCAL5)] = "local5",
1986 [LOG_FAC(LOG_LOCAL6)] = "local6",
1987 [LOG_FAC(LOG_LOCAL7)] = "local7"
1988};
1989
1990DEFINE_STRING_TABLE_LOOKUP(log_facility, int);
1991
1992static const char *const log_level_table[] = {
1993 [LOG_EMERG] = "emerg",
1994 [LOG_ALERT] = "alert",
1995 [LOG_CRIT] = "crit",
1996 [LOG_ERR] = "err",
1997 [LOG_WARNING] = "warning",
1998 [LOG_NOTICE] = "notice",
1999 [LOG_INFO] = "info",
2000 [LOG_DEBUG] = "debug"
2001};
2002
2003DEFINE_STRING_TABLE_LOOKUP(log_level, int);
2004
2005static const char* const sched_policy_table[] = {
2006 [SCHED_OTHER] = "other",
2007 [SCHED_BATCH] = "batch",
2008 [SCHED_IDLE] = "idle",
2009 [SCHED_FIFO] = "fifo",
2010 [SCHED_RR] = "rr"
2011};
2012
2013DEFINE_STRING_TABLE_LOOKUP(sched_policy, int);
2014
2015static const char* const rlimit_table[] = {
2016 [RLIMIT_CPU] = "LimitCPU",
2017 [RLIMIT_FSIZE] = "LimitFSIZE",
2018 [RLIMIT_DATA] = "LimitDATA",
2019 [RLIMIT_STACK] = "LimitSTACK",
2020 [RLIMIT_CORE] = "LimitCORE",
2021 [RLIMIT_RSS] = "LimitRSS",
2022 [RLIMIT_NOFILE] = "LimitNOFILE",
2023 [RLIMIT_AS] = "LimitAS",
2024 [RLIMIT_NPROC] = "LimitNPROC",
2025 [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
2026 [RLIMIT_LOCKS] = "LimitLOCKS",
2027 [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
2028 [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
2029 [RLIMIT_NICE] = "LimitNICE",
2030 [RLIMIT_RTPRIO] = "LimitRTPRIO",
2031 [RLIMIT_RTTIME] = "LimitRTTIME"
2032};
2033
2034DEFINE_STRING_TABLE_LOOKUP(rlimit, int);