]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/util.c
conf-parser: support continuation lines with trailing backslashes in lines
[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>
5b6319dc 46#include <sys/prctl.h>
ef2f1067
LP
47#include <sys/utsname.h>
48#include <pwd.h>
4fd5948e 49#include <netinet/ip.h>
60918275
LP
50
51#include "macro.h"
52#include "util.h"
1dccbe19
LP
53#include "ioprio.h"
54#include "missing.h"
a9f5d454 55#include "log.h"
65d2ebdc 56#include "strv.h"
60918275 57
e05797fb
LP
58bool streq_ptr(const char *a, const char *b) {
59
60 /* Like streq(), but tries to make sense of NULL pointers */
61
62 if (a && b)
63 return streq(a, b);
64
65 if (!a && !b)
66 return true;
67
68 return false;
69}
70
47be870b 71usec_t now(clockid_t clock_id) {
60918275
LP
72 struct timespec ts;
73
47be870b 74 assert_se(clock_gettime(clock_id, &ts) == 0);
60918275
LP
75
76 return timespec_load(&ts);
77}
78
63983207 79dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
871d7de4
LP
80 assert(ts);
81
82 ts->realtime = now(CLOCK_REALTIME);
83 ts->monotonic = now(CLOCK_MONOTONIC);
84
85 return ts;
86}
87
60918275
LP
88usec_t timespec_load(const struct timespec *ts) {
89 assert(ts);
90
91 return
92 (usec_t) ts->tv_sec * USEC_PER_SEC +
93 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
94}
95
96struct timespec *timespec_store(struct timespec *ts, usec_t u) {
97 assert(ts);
98
99 ts->tv_sec = (time_t) (u / USEC_PER_SEC);
100 ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
101
102 return ts;
103}
104
105usec_t timeval_load(const struct timeval *tv) {
106 assert(tv);
107
108 return
109 (usec_t) tv->tv_sec * USEC_PER_SEC +
110 (usec_t) tv->tv_usec;
111}
112
113struct timeval *timeval_store(struct timeval *tv, usec_t u) {
114 assert(tv);
115
116 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
117 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
118
119 return tv;
120}
121
122bool endswith(const char *s, const char *postfix) {
123 size_t sl, pl;
124
125 assert(s);
126 assert(postfix);
127
128 sl = strlen(s);
129 pl = strlen(postfix);
130
d4d0d4db
LP
131 if (pl == 0)
132 return true;
133
60918275
LP
134 if (sl < pl)
135 return false;
136
137 return memcmp(s + sl - pl, postfix, pl) == 0;
138}
139
140bool startswith(const char *s, const char *prefix) {
141 size_t sl, pl;
142
143 assert(s);
144 assert(prefix);
145
146 sl = strlen(s);
147 pl = strlen(prefix);
148
d4d0d4db
LP
149 if (pl == 0)
150 return true;
151
60918275
LP
152 if (sl < pl)
153 return false;
154
155 return memcmp(s, prefix, pl) == 0;
156}
157
3177a7fa
MAP
158bool startswith_no_case(const char *s, const char *prefix) {
159 size_t sl, pl;
160 unsigned i;
161
162 assert(s);
163 assert(prefix);
164
165 sl = strlen(s);
166 pl = strlen(prefix);
167
168 if (pl == 0)
169 return true;
170
171 if (sl < pl)
172 return false;
173
174 for(i = 0; i < pl; ++i) {
175 if (tolower(s[i]) != tolower(prefix[i]))
176 return false;
177 }
178
179 return true;
180}
181
79d6d816
LP
182bool first_word(const char *s, const char *word) {
183 size_t sl, wl;
184
185 assert(s);
186 assert(word);
187
188 sl = strlen(s);
189 wl = strlen(word);
190
191 if (sl < wl)
192 return false;
193
d4d0d4db
LP
194 if (wl == 0)
195 return true;
196
79d6d816
LP
197 if (memcmp(s, word, wl) != 0)
198 return false;
199
d4d0d4db
LP
200 return s[wl] == 0 ||
201 strchr(WHITESPACE, s[wl]);
79d6d816
LP
202}
203
42f4e3c4 204int close_nointr(int fd) {
60918275
LP
205 assert(fd >= 0);
206
207 for (;;) {
208 int r;
209
210 if ((r = close(fd)) >= 0)
211 return r;
212
213 if (errno != EINTR)
214 return r;
215 }
216}
85261803 217
85f136b5 218void close_nointr_nofail(int fd) {
80876c20 219 int saved_errno = errno;
85f136b5
LP
220
221 /* like close_nointr() but cannot fail, and guarantees errno
222 * is unchanged */
223
224 assert_se(close_nointr(fd) == 0);
80876c20
LP
225
226 errno = saved_errno;
85f136b5
LP
227}
228
5b6319dc
LP
229void close_many(const int fds[], unsigned n_fd) {
230 unsigned i;
231
232 for (i = 0; i < n_fd; i++)
233 close_nointr_nofail(fds[i]);
234}
235
85261803
LP
236int parse_boolean(const char *v) {
237 assert(v);
238
44d8db9e 239 if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
85261803 240 return 1;
44d8db9e 241 else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
85261803
LP
242 return 0;
243
244 return -EINVAL;
245}
246
3ba686c1
LP
247int parse_pid(const char *s, pid_t* ret_pid) {
248 unsigned long ul;
249 pid_t pid;
250 int r;
251
252 assert(s);
253 assert(ret_pid);
254
255 if ((r = safe_atolu(s, &ul)) < 0)
256 return r;
257
258 pid = (pid_t) ul;
259
260 if ((unsigned long) pid != ul)
261 return -ERANGE;
262
263 if (pid <= 0)
264 return -ERANGE;
265
266 *ret_pid = pid;
267 return 0;
268}
269
85261803
LP
270int safe_atou(const char *s, unsigned *ret_u) {
271 char *x = NULL;
034c6ed7 272 unsigned long l;
85261803
LP
273
274 assert(s);
275 assert(ret_u);
276
277 errno = 0;
278 l = strtoul(s, &x, 0);
279
280 if (!x || *x || errno)
281 return errno ? -errno : -EINVAL;
282
034c6ed7 283 if ((unsigned long) (unsigned) l != l)
85261803
LP
284 return -ERANGE;
285
286 *ret_u = (unsigned) l;
287 return 0;
288}
289
290int safe_atoi(const char *s, int *ret_i) {
291 char *x = NULL;
034c6ed7 292 long l;
85261803
LP
293
294 assert(s);
295 assert(ret_i);
296
297 errno = 0;
298 l = strtol(s, &x, 0);
299
300 if (!x || *x || errno)
301 return errno ? -errno : -EINVAL;
302
034c6ed7 303 if ((long) (int) l != l)
85261803
LP
304 return -ERANGE;
305
034c6ed7
LP
306 *ret_i = (int) l;
307 return 0;
308}
309
034c6ed7
LP
310int safe_atollu(const char *s, long long unsigned *ret_llu) {
311 char *x = NULL;
312 unsigned long long l;
313
314 assert(s);
315 assert(ret_llu);
316
317 errno = 0;
318 l = strtoull(s, &x, 0);
319
320 if (!x || *x || errno)
321 return errno ? -errno : -EINVAL;
322
323 *ret_llu = l;
324 return 0;
325}
326
327int safe_atolli(const char *s, long long int *ret_lli) {
328 char *x = NULL;
329 long long l;
330
331 assert(s);
332 assert(ret_lli);
333
334 errno = 0;
335 l = strtoll(s, &x, 0);
336
337 if (!x || *x || errno)
338 return errno ? -errno : -EINVAL;
339
340 *ret_lli = l;
85261803
LP
341 return 0;
342}
a41e8209 343
a41e8209 344/* Split a string into words. */
65d2ebdc 345char *split(const char *c, size_t *l, const char *separator, char **state) {
a41e8209
LP
346 char *current;
347
348 current = *state ? *state : (char*) c;
349
350 if (!*current || *c == 0)
351 return NULL;
352
65d2ebdc
LP
353 current += strspn(current, separator);
354 *l = strcspn(current, separator);
82919e3d
LP
355 *state = current+*l;
356
357 return (char*) current;
358}
359
034c6ed7
LP
360/* Split a string into words, but consider strings enclosed in '' and
361 * "" as words even if they include spaces. */
362char *split_quoted(const char *c, size_t *l, char **state) {
363 char *current;
364
365 current = *state ? *state : (char*) c;
366
367 if (!*current || *c == 0)
368 return NULL;
369
370 current += strspn(current, WHITESPACE);
371
372 if (*current == '\'') {
373 current ++;
374 *l = strcspn(current, "'");
375 *state = current+*l;
376
377 if (**state == '\'')
378 (*state)++;
379 } else if (*current == '\"') {
380 current ++;
b858b600 381 *l = strcspn(current, "\"");
034c6ed7
LP
382 *state = current+*l;
383
384 if (**state == '\"')
385 (*state)++;
386 } else {
387 *l = strcspn(current, WHITESPACE);
388 *state = current+*l;
389 }
390
44d8db9e
LP
391 /* FIXME: Cannot deal with strings that have spaces AND ticks
392 * in them */
393
034c6ed7
LP
394 return (char*) current;
395}
396
65d2ebdc
LP
397char **split_path_and_make_absolute(const char *p) {
398 char **l;
399 assert(p);
400
401 if (!(l = strv_split(p, ":")))
402 return NULL;
403
404 if (!strv_path_make_absolute_cwd(l)) {
405 strv_free(l);
406 return NULL;
407 }
408
409 return l;
410}
411
034c6ed7
LP
412int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
413 int r;
414 FILE *f;
415 char fn[132], line[256], *p;
bb00e604 416 long unsigned ppid;
034c6ed7
LP
417
418 assert(pid >= 0);
419 assert(_ppid);
420
bb00e604 421 assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%lu/stat", (unsigned long) pid) < (int) (sizeof(fn)-1));
034c6ed7
LP
422 fn[sizeof(fn)-1] = 0;
423
424 if (!(f = fopen(fn, "r")))
425 return -errno;
426
427 if (!(fgets(line, sizeof(line), f))) {
428 r = -errno;
429 fclose(f);
430 return r;
431 }
432
433 fclose(f);
434
435 /* Let's skip the pid and comm fields. The latter is enclosed
436 * in () but does not escape any () in its value, so let's
437 * skip over it manually */
438
439 if (!(p = strrchr(line, ')')))
440 return -EIO;
441
442 p++;
443
444 if (sscanf(p, " "
445 "%*c " /* state */
bb00e604 446 "%lu ", /* ppid */
034c6ed7
LP
447 &ppid) != 1)
448 return -EIO;
449
bb00e604 450 if ((long unsigned) (pid_t) ppid != ppid)
034c6ed7
LP
451 return -ERANGE;
452
453 *_ppid = (pid_t) ppid;
454
455 return 0;
456}
457
458int write_one_line_file(const char *fn, const char *line) {
459 FILE *f;
460 int r;
461
462 assert(fn);
463 assert(line);
464
465 if (!(f = fopen(fn, "we")))
466 return -errno;
467
468 if (fputs(line, f) < 0) {
469 r = -errno;
470 goto finish;
471 }
472
473 r = 0;
474finish:
475 fclose(f);
476 return r;
477}
478
479int read_one_line_file(const char *fn, char **line) {
480 FILE *f;
481 int r;
11316633 482 char t[2048], *c;
034c6ed7
LP
483
484 assert(fn);
485 assert(line);
486
487 if (!(f = fopen(fn, "re")))
488 return -errno;
489
490 if (!(fgets(t, sizeof(t), f))) {
491 r = -errno;
492 goto finish;
493 }
494
495 if (!(c = strdup(t))) {
496 r = -ENOMEM;
497 goto finish;
498 }
499
500 *line = c;
501 r = 0;
502
503finish:
504 fclose(f);
505 return r;
506}
44d8db9e 507
7072ced8
LP
508char *truncate_nl(char *s) {
509 assert(s);
510
511 s[strcspn(s, NEWLINE)] = 0;
512 return s;
513}
514
515int get_process_name(pid_t pid, char **name) {
516 char *p;
517 int r;
518
519 assert(pid >= 1);
520 assert(name);
521
bb00e604 522 if (asprintf(&p, "/proc/%lu/comm", (unsigned long) pid) < 0)
7072ced8
LP
523 return -ENOMEM;
524
525 r = read_one_line_file(p, name);
526 free(p);
527
528 if (r < 0)
529 return r;
530
531 truncate_nl(*name);
532 return 0;
533}
534
c59760ee
LP
535int get_process_cmdline(pid_t pid, size_t max_length, char **line) {
536 char *p, *r, *k;
537 int c;
538 bool space = false;
539 size_t left;
540 FILE *f;
541
542 assert(pid >= 1);
543 assert(max_length > 0);
544 assert(line);
545
546 if (asprintf(&p, "/proc/%lu/cmdline", (unsigned long) pid) < 0)
547 return -ENOMEM;
548
549 f = fopen(p, "r");
550 free(p);
551
552 if (!f)
553 return -errno;
554
555 if (!(r = new(char, max_length))) {
556 fclose(f);
557 return -ENOMEM;
558 }
559
560 k = r;
561 left = max_length;
562 while ((c = getc(f)) != EOF) {
563
564 if (isprint(c)) {
565 if (space) {
566 if (left <= 4)
567 break;
568
569 *(k++) = ' ';
057fbb58 570 left--;
c59760ee
LP
571 space = false;
572 }
573
574 if (left <= 4)
575 break;
576
577 *(k++) = (char) c;
057fbb58 578 left--;
c59760ee
LP
579 } else
580 space = true;
581 }
582
583 if (left <= 4) {
584 size_t n = MIN(left-1, 3U);
585 memcpy(k, "...", n);
586 k[n] = 0;
587 } else
588 *k = 0;
589
590 fclose(f);
591
592 *line = r;
593 return 0;
594}
595
44d8db9e
LP
596char *strappend(const char *s, const char *suffix) {
597 size_t a, b;
598 char *r;
599
600 assert(s);
601 assert(suffix);
602
603 a = strlen(s);
604 b = strlen(suffix);
605
606 if (!(r = new(char, a+b+1)))
607 return NULL;
608
609 memcpy(r, s, a);
610 memcpy(r+a, suffix, b);
611 r[a+b] = 0;
612
613 return r;
614}
87f0e418
LP
615
616int readlink_malloc(const char *p, char **r) {
617 size_t l = 100;
618
619 assert(p);
620 assert(r);
621
622 for (;;) {
623 char *c;
624 ssize_t n;
625
626 if (!(c = new(char, l)))
627 return -ENOMEM;
628
629 if ((n = readlink(p, c, l-1)) < 0) {
630 int ret = -errno;
631 free(c);
632 return ret;
633 }
634
635 if ((size_t) n < l-1) {
636 c[n] = 0;
637 *r = c;
638 return 0;
639 }
640
641 free(c);
642 l *= 2;
643 }
644}
645
2c7108c4
LP
646int readlink_and_make_absolute(const char *p, char **r) {
647 char *target, *k;
648 int j;
649
650 assert(p);
651 assert(r);
652
653 if ((j = readlink_malloc(p, &target)) < 0)
654 return j;
655
656 k = file_in_same_dir(p, target);
657 free(target);
658
659 if (!k)
660 return -ENOMEM;
661
662 *r = k;
663 return 0;
664}
665
87f0e418
LP
666char *file_name_from_path(const char *p) {
667 char *r;
668
669 assert(p);
670
671 if ((r = strrchr(p, '/')))
672 return r + 1;
673
674 return (char*) p;
675}
0301abf4
LP
676
677bool path_is_absolute(const char *p) {
678 assert(p);
679
680 return p[0] == '/';
681}
682
683bool is_path(const char *p) {
684
685 return !!strchr(p, '/');
686}
687
688char *path_make_absolute(const char *p, const char *prefix) {
689 char *r;
690
691 assert(p);
692
65d2ebdc
LP
693 /* Makes every item in the list an absolute path by prepending
694 * the prefix, if specified and necessary */
695
0301abf4
LP
696 if (path_is_absolute(p) || !prefix)
697 return strdup(p);
698
699 if (asprintf(&r, "%s/%s", prefix, p) < 0)
700 return NULL;
701
702 return r;
703}
2a987ee8 704
65d2ebdc
LP
705char *path_make_absolute_cwd(const char *p) {
706 char *cwd, *r;
707
708 assert(p);
709
710 /* Similar to path_make_absolute(), but prefixes with the
711 * current working directory. */
712
713 if (path_is_absolute(p))
714 return strdup(p);
715
716 if (!(cwd = get_current_dir_name()))
717 return NULL;
718
719 r = path_make_absolute(p, cwd);
720 free(cwd);
721
722 return r;
723}
724
725char **strv_path_make_absolute_cwd(char **l) {
726 char **s;
727
728 /* Goes through every item in the string list and makes it
729 * absolute. This works in place and won't rollback any
730 * changes on failure. */
731
732 STRV_FOREACH(s, l) {
733 char *t;
734
735 if (!(t = path_make_absolute_cwd(*s)))
736 return NULL;
737
738 free(*s);
739 *s = t;
740 }
741
742 return l;
743}
744
c3f6d675
LP
745char **strv_path_canonicalize(char **l) {
746 char **s;
747 unsigned k = 0;
748 bool enomem = false;
749
750 if (strv_isempty(l))
751 return l;
752
753 /* Goes through every item in the string list and canonicalize
754 * the path. This works in place and won't rollback any
755 * changes on failure. */
756
757 STRV_FOREACH(s, l) {
758 char *t, *u;
759
760 t = path_make_absolute_cwd(*s);
761 free(*s);
762
763 if (!t) {
764 enomem = true;
765 continue;
766 }
767
768 errno = 0;
769 u = canonicalize_file_name(t);
770 free(t);
771
772 if (!u) {
773 if (errno == ENOMEM || !errno)
774 enomem = true;
775
776 continue;
777 }
778
779 l[k++] = u;
780 }
781
782 l[k] = NULL;
783
784 if (enomem)
785 return NULL;
786
787 return l;
788}
789
2a987ee8
LP
790int reset_all_signal_handlers(void) {
791 int sig;
792
793 for (sig = 1; sig < _NSIG; sig++) {
794 struct sigaction sa;
795
796 if (sig == SIGKILL || sig == SIGSTOP)
797 continue;
798
799 zero(sa);
800 sa.sa_handler = SIG_DFL;
431c32bf 801 sa.sa_flags = SA_RESTART;
2a987ee8
LP
802
803 /* On Linux the first two RT signals are reserved by
804 * glibc, and sigaction() will return EINVAL for them. */
805 if ((sigaction(sig, &sa, NULL) < 0))
806 if (errno != EINVAL)
807 return -errno;
808 }
809
8e274523 810 return 0;
2a987ee8 811}
4a72ff34
LP
812
813char *strstrip(char *s) {
814 char *e, *l = NULL;
815
816 /* Drops trailing whitespace. Modifies the string in
817 * place. Returns pointer to first non-space character */
818
819 s += strspn(s, WHITESPACE);
820
821 for (e = s; *e; e++)
822 if (!strchr(WHITESPACE, *e))
823 l = e;
824
825 if (l)
826 *(l+1) = 0;
827 else
828 *s = 0;
829
830 return s;
4a72ff34
LP
831}
832
ee9b5e01
LP
833char *delete_chars(char *s, const char *bad) {
834 char *f, *t;
835
836 /* Drops all whitespace, regardless where in the string */
837
838 for (f = s, t = s; *f; f++) {
839 if (strchr(bad, *f))
840 continue;
841
842 *(t++) = *f;
843 }
844
845 *t = 0;
846
847 return s;
848}
849
4a72ff34
LP
850char *file_in_same_dir(const char *path, const char *filename) {
851 char *e, *r;
852 size_t k;
853
854 assert(path);
855 assert(filename);
856
857 /* This removes the last component of path and appends
858 * filename, unless the latter is absolute anyway or the
859 * former isn't */
860
861 if (path_is_absolute(filename))
862 return strdup(filename);
863
864 if (!(e = strrchr(path, '/')))
865 return strdup(filename);
866
867 k = strlen(filename);
868 if (!(r = new(char, e-path+1+k+1)))
869 return NULL;
870
871 memcpy(r, path, e-path+1);
872 memcpy(r+(e-path)+1, filename, k+1);
873
874 return r;
875}
fb624d04 876
8c6db833
LP
877int safe_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid) {
878 struct stat st;
879
880 if (mkdir(path, mode) >= 0)
881 if (chmod_and_chown(path, mode, uid, gid) < 0)
882 return -errno;
883
884 if (lstat(path, &st) < 0)
885 return -errno;
886
887 if ((st.st_mode & 0777) != mode ||
888 st.st_uid != uid ||
889 st.st_gid != gid ||
890 !S_ISDIR(st.st_mode)) {
891 errno = EEXIST;
892 return -errno;
893 }
894
895 return 0;
896}
897
898
a9f5d454
LP
899int mkdir_parents(const char *path, mode_t mode) {
900 const char *p, *e;
901
902 assert(path);
903
904 /* Creates every parent directory in the path except the last
905 * component. */
906
907 p = path + strspn(path, "/");
908 for (;;) {
909 int r;
910 char *t;
911
912 e = p + strcspn(p, "/");
913 p = e + strspn(e, "/");
914
915 /* Is this the last component? If so, then we're
916 * done */
917 if (*p == 0)
918 return 0;
919
920 if (!(t = strndup(path, e - path)))
921 return -ENOMEM;
922
923 r = mkdir(t, mode);
924
925 free(t);
926
927 if (r < 0 && errno != EEXIST)
928 return -errno;
929 }
930}
931
bbd67135
LP
932int mkdir_p(const char *path, mode_t mode) {
933 int r;
934
935 /* Like mkdir -p */
936
937 if ((r = mkdir_parents(path, mode)) < 0)
938 return r;
939
940 if (mkdir(path, mode) < 0)
941 return -errno;
942
943 return 0;
944}
945
c32dd69b
LP
946int rmdir_parents(const char *path, const char *stop) {
947 size_t l;
948 int r = 0;
949
950 assert(path);
951 assert(stop);
952
953 l = strlen(path);
954
955 /* Skip trailing slashes */
956 while (l > 0 && path[l-1] == '/')
957 l--;
958
959 while (l > 0) {
960 char *t;
961
962 /* Skip last component */
963 while (l > 0 && path[l-1] != '/')
964 l--;
965
966 /* Skip trailing slashes */
967 while (l > 0 && path[l-1] == '/')
968 l--;
969
970 if (l <= 0)
971 break;
972
973 if (!(t = strndup(path, l)))
974 return -ENOMEM;
975
976 if (path_startswith(stop, t)) {
977 free(t);
978 return 0;
979 }
980
981 r = rmdir(t);
982 free(t);
983
984 if (r < 0)
985 if (errno != ENOENT)
986 return -errno;
987 }
988
989 return 0;
990}
991
992
fb624d04
LP
993char hexchar(int x) {
994 static const char table[16] = "0123456789abcdef";
995
996 return table[x & 15];
997}
4fe88d28
LP
998
999int unhexchar(char c) {
1000
1001 if (c >= '0' && c <= '9')
1002 return c - '0';
1003
1004 if (c >= 'a' && c <= 'f')
ea430986 1005 return c - 'a' + 10;
4fe88d28
LP
1006
1007 if (c >= 'A' && c <= 'F')
ea430986 1008 return c - 'A' + 10;
4fe88d28
LP
1009
1010 return -1;
1011}
1012
1013char octchar(int x) {
1014 return '0' + (x & 7);
1015}
1016
1017int unoctchar(char c) {
1018
1019 if (c >= '0' && c <= '7')
1020 return c - '0';
1021
1022 return -1;
1023}
1024
5af98f82
LP
1025char decchar(int x) {
1026 return '0' + (x % 10);
1027}
1028
1029int undecchar(char c) {
1030
1031 if (c >= '0' && c <= '9')
1032 return c - '0';
1033
1034 return -1;
1035}
1036
4fe88d28
LP
1037char *cescape(const char *s) {
1038 char *r, *t;
1039 const char *f;
1040
1041 assert(s);
1042
1043 /* Does C style string escaping. */
1044
1045 if (!(r = new(char, strlen(s)*4 + 1)))
1046 return NULL;
1047
1048 for (f = s, t = r; *f; f++)
1049
1050 switch (*f) {
1051
1052 case '\a':
1053 *(t++) = '\\';
1054 *(t++) = 'a';
1055 break;
1056 case '\b':
1057 *(t++) = '\\';
1058 *(t++) = 'b';
1059 break;
1060 case '\f':
1061 *(t++) = '\\';
1062 *(t++) = 'f';
1063 break;
1064 case '\n':
1065 *(t++) = '\\';
1066 *(t++) = 'n';
1067 break;
1068 case '\r':
1069 *(t++) = '\\';
1070 *(t++) = 'r';
1071 break;
1072 case '\t':
1073 *(t++) = '\\';
1074 *(t++) = 't';
1075 break;
1076 case '\v':
1077 *(t++) = '\\';
1078 *(t++) = 'v';
1079 break;
1080 case '\\':
1081 *(t++) = '\\';
1082 *(t++) = '\\';
1083 break;
1084 case '"':
1085 *(t++) = '\\';
1086 *(t++) = '"';
1087 break;
1088 case '\'':
1089 *(t++) = '\\';
1090 *(t++) = '\'';
1091 break;
1092
1093 default:
1094 /* For special chars we prefer octal over
1095 * hexadecimal encoding, simply because glib's
1096 * g_strescape() does the same */
1097 if ((*f < ' ') || (*f >= 127)) {
1098 *(t++) = '\\';
1099 *(t++) = octchar((unsigned char) *f >> 6);
1100 *(t++) = octchar((unsigned char) *f >> 3);
1101 *(t++) = octchar((unsigned char) *f);
1102 } else
1103 *(t++) = *f;
1104 break;
1105 }
1106
1107 *t = 0;
1108
1109 return r;
1110}
1111
1112char *cunescape(const char *s) {
1113 char *r, *t;
1114 const char *f;
1115
1116 assert(s);
1117
1118 /* Undoes C style string escaping */
1119
1120 if (!(r = new(char, strlen(s)+1)))
1121 return r;
1122
1123 for (f = s, t = r; *f; f++) {
1124
1125 if (*f != '\\') {
1126 *(t++) = *f;
1127 continue;
1128 }
1129
1130 f++;
1131
1132 switch (*f) {
1133
1134 case 'a':
1135 *(t++) = '\a';
1136 break;
1137 case 'b':
1138 *(t++) = '\b';
1139 break;
1140 case 'f':
1141 *(t++) = '\f';
1142 break;
1143 case 'n':
1144 *(t++) = '\n';
1145 break;
1146 case 'r':
1147 *(t++) = '\r';
1148 break;
1149 case 't':
1150 *(t++) = '\t';
1151 break;
1152 case 'v':
1153 *(t++) = '\v';
1154 break;
1155 case '\\':
1156 *(t++) = '\\';
1157 break;
1158 case '"':
1159 *(t++) = '"';
1160 break;
1161 case '\'':
1162 *(t++) = '\'';
1163 break;
1164
1165 case 'x': {
1166 /* hexadecimal encoding */
1167 int a, b;
1168
1169 if ((a = unhexchar(f[1])) < 0 ||
1170 (b = unhexchar(f[2])) < 0) {
1171 /* Invalid escape code, let's take it literal then */
1172 *(t++) = '\\';
1173 *(t++) = 'x';
1174 } else {
1175 *(t++) = (char) ((a << 4) | b);
1176 f += 2;
1177 }
1178
1179 break;
1180 }
1181
1182 case '0':
1183 case '1':
1184 case '2':
1185 case '3':
1186 case '4':
1187 case '5':
1188 case '6':
1189 case '7': {
1190 /* octal encoding */
1191 int a, b, c;
1192
1193 if ((a = unoctchar(f[0])) < 0 ||
1194 (b = unoctchar(f[1])) < 0 ||
1195 (c = unoctchar(f[2])) < 0) {
1196 /* Invalid escape code, let's take it literal then */
1197 *(t++) = '\\';
1198 *(t++) = f[0];
1199 } else {
1200 *(t++) = (char) ((a << 6) | (b << 3) | c);
1201 f += 2;
1202 }
1203
1204 break;
1205 }
1206
1207 case 0:
1208 /* premature end of string.*/
1209 *(t++) = '\\';
1210 goto finish;
1211
1212 default:
1213 /* Invalid escape code, let's take it literal then */
1214 *(t++) = '\\';
1215 *(t++) = 'f';
1216 break;
1217 }
1218 }
1219
1220finish:
1221 *t = 0;
1222 return r;
1223}
1224
1225
1226char *xescape(const char *s, const char *bad) {
1227 char *r, *t;
1228 const char *f;
1229
1230 /* Escapes all chars in bad, in addition to \ and all special
1231 * chars, in \xFF style escaping. May be reversed with
1232 * cunescape. */
1233
1234 if (!(r = new(char, strlen(s)*4+1)))
1235 return NULL;
1236
1237 for (f = s, t = r; *f; f++) {
1238
b866264a
LP
1239 if ((*f < ' ') || (*f >= 127) ||
1240 (*f == '\\') || strchr(bad, *f)) {
4fe88d28
LP
1241 *(t++) = '\\';
1242 *(t++) = 'x';
1243 *(t++) = hexchar(*f >> 4);
1244 *(t++) = hexchar(*f);
1245 } else
1246 *(t++) = *f;
1247 }
1248
1249 *t = 0;
1250
1251 return r;
1252}
1253
ea430986 1254char *bus_path_escape(const char *s) {
ea430986
LP
1255 char *r, *t;
1256 const char *f;
1257
47be870b
LP
1258 assert(s);
1259
ea430986
LP
1260 /* Escapes all chars that D-Bus' object path cannot deal
1261 * with. Can be reverse with bus_path_unescape() */
1262
1263 if (!(r = new(char, strlen(s)*3+1)))
1264 return NULL;
1265
1266 for (f = s, t = r; *f; f++) {
1267
1268 if (!(*f >= 'A' && *f <= 'Z') &&
1269 !(*f >= 'a' && *f <= 'z') &&
1270 !(*f >= '0' && *f <= '9')) {
1271 *(t++) = '_';
1272 *(t++) = hexchar(*f >> 4);
1273 *(t++) = hexchar(*f);
1274 } else
1275 *(t++) = *f;
1276 }
1277
1278 *t = 0;
1279
1280 return r;
1281}
1282
9e2f7c11 1283char *bus_path_unescape(const char *f) {
ea430986 1284 char *r, *t;
ea430986 1285
9e2f7c11 1286 assert(f);
47be870b 1287
9e2f7c11 1288 if (!(r = strdup(f)))
ea430986
LP
1289 return NULL;
1290
9e2f7c11 1291 for (t = r; *f; f++) {
ea430986
LP
1292
1293 if (*f == '_') {
1294 int a, b;
1295
1296 if ((a = unhexchar(f[1])) < 0 ||
1297 (b = unhexchar(f[2])) < 0) {
1298 /* Invalid escape code, let's take it literal then */
1299 *(t++) = '_';
1300 } else {
1301 *(t++) = (char) ((a << 4) | b);
1302 f += 2;
1303 }
1304 } else
1305 *(t++) = *f;
1306 }
1307
1308 *t = 0;
1309
1310 return r;
1311}
1312
4fe88d28
LP
1313char *path_kill_slashes(char *path) {
1314 char *f, *t;
1315 bool slash = false;
1316
1317 /* Removes redundant inner and trailing slashes. Modifies the
1318 * passed string in-place.
1319 *
1320 * ///foo///bar/ becomes /foo/bar
1321 */
1322
1323 for (f = path, t = path; *f; f++) {
1324
1325 if (*f == '/') {
1326 slash = true;
1327 continue;
1328 }
1329
1330 if (slash) {
1331 slash = false;
1332 *(t++) = '/';
1333 }
1334
1335 *(t++) = *f;
1336 }
1337
1338 /* Special rule, if we are talking of the root directory, a
1339 trailing slash is good */
1340
1341 if (t == path && slash)
1342 *(t++) = '/';
1343
1344 *t = 0;
1345 return path;
1346}
1347
1348bool path_startswith(const char *path, const char *prefix) {
1349 assert(path);
1350 assert(prefix);
1351
1352 if ((path[0] == '/') != (prefix[0] == '/'))
1353 return false;
1354
1355 for (;;) {
1356 size_t a, b;
1357
1358 path += strspn(path, "/");
1359 prefix += strspn(prefix, "/");
1360
1361 if (*prefix == 0)
1362 return true;
1363
1364 if (*path == 0)
1365 return false;
1366
1367 a = strcspn(path, "/");
1368 b = strcspn(prefix, "/");
1369
1370 if (a != b)
1371 return false;
1372
1373 if (memcmp(path, prefix, a) != 0)
1374 return false;
1375
1376 path += a;
1377 prefix += b;
1378 }
1379}
1380
15ae422b
LP
1381bool path_equal(const char *a, const char *b) {
1382 assert(a);
1383 assert(b);
1384
1385 if ((a[0] == '/') != (b[0] == '/'))
1386 return false;
1387
1388 for (;;) {
1389 size_t j, k;
1390
1391 a += strspn(a, "/");
1392 b += strspn(b, "/");
1393
1394 if (*a == 0 && *b == 0)
1395 return true;
1396
1397 if (*a == 0 || *b == 0)
1398 return false;
1399
1400 j = strcspn(a, "/");
1401 k = strcspn(b, "/");
1402
1403 if (j != k)
1404 return false;
1405
1406 if (memcmp(a, b, j) != 0)
1407 return false;
1408
1409 a += j;
1410 b += k;
1411 }
1412}
1413
67d51650 1414char *ascii_strlower(char *t) {
4fe88d28
LP
1415 char *p;
1416
67d51650 1417 assert(t);
4fe88d28 1418
67d51650 1419 for (p = t; *p; p++)
4fe88d28
LP
1420 if (*p >= 'A' && *p <= 'Z')
1421 *p = *p - 'A' + 'a';
1422
67d51650 1423 return t;
4fe88d28 1424}
1dccbe19 1425
c85dc17b
LP
1426bool ignore_file(const char *filename) {
1427 assert(filename);
1428
1429 return
1430 filename[0] == '.' ||
6c78be3c 1431 streq(filename, "lost+found") ||
c85dc17b
LP
1432 endswith(filename, "~") ||
1433 endswith(filename, ".rpmnew") ||
1434 endswith(filename, ".rpmsave") ||
1435 endswith(filename, ".rpmorig") ||
1436 endswith(filename, ".dpkg-old") ||
1437 endswith(filename, ".dpkg-new") ||
1438 endswith(filename, ".swp");
1439}
1440
3a0ecb08
LP
1441int fd_nonblock(int fd, bool nonblock) {
1442 int flags;
1443
1444 assert(fd >= 0);
1445
1446 if ((flags = fcntl(fd, F_GETFL, 0)) < 0)
1447 return -errno;
1448
1449 if (nonblock)
1450 flags |= O_NONBLOCK;
1451 else
1452 flags &= ~O_NONBLOCK;
1453
1454 if (fcntl(fd, F_SETFL, flags) < 0)
1455 return -errno;
1456
1457 return 0;
1458}
1459
1460int fd_cloexec(int fd, bool cloexec) {
1461 int flags;
1462
1463 assert(fd >= 0);
1464
1465 if ((flags = fcntl(fd, F_GETFD, 0)) < 0)
1466 return -errno;
1467
1468 if (cloexec)
1469 flags |= FD_CLOEXEC;
1470 else
1471 flags &= ~FD_CLOEXEC;
1472
1473 if (fcntl(fd, F_SETFD, flags) < 0)
1474 return -errno;
1475
1476 return 0;
1477}
1478
a0d40ac5
LP
1479int close_all_fds(const int except[], unsigned n_except) {
1480 DIR *d;
1481 struct dirent *de;
1482 int r = 0;
1483
1484 if (!(d = opendir("/proc/self/fd")))
1485 return -errno;
1486
1487 while ((de = readdir(d))) {
a7610064 1488 int fd = -1;
a0d40ac5 1489
a16e1123 1490 if (ignore_file(de->d_name))
a0d40ac5
LP
1491 continue;
1492
1493 if ((r = safe_atoi(de->d_name, &fd)) < 0)
1494 goto finish;
1495
1496 if (fd < 3)
1497 continue;
1498
1499 if (fd == dirfd(d))
1500 continue;
1501
1502 if (except) {
1503 bool found;
1504 unsigned i;
1505
1506 found = false;
1507 for (i = 0; i < n_except; i++)
1508 if (except[i] == fd) {
1509 found = true;
1510 break;
1511 }
1512
1513 if (found)
1514 continue;
1515 }
1516
2f357920
LP
1517 if ((r = close_nointr(fd)) < 0) {
1518 /* Valgrind has its own FD and doesn't want to have it closed */
1519 if (errno != EBADF)
1520 goto finish;
1521 }
a0d40ac5
LP
1522 }
1523
2f357920
LP
1524 r = 0;
1525
a0d40ac5
LP
1526finish:
1527 closedir(d);
1528 return r;
1529}
1530
db12775d
LP
1531bool chars_intersect(const char *a, const char *b) {
1532 const char *p;
1533
1534 /* Returns true if any of the chars in a are in b. */
1535 for (p = a; *p; p++)
1536 if (strchr(b, *p))
1537 return true;
1538
1539 return false;
1540}
1541
8b6c7120
LP
1542char *format_timestamp(char *buf, size_t l, usec_t t) {
1543 struct tm tm;
1544 time_t sec;
1545
1546 assert(buf);
1547 assert(l > 0);
1548
1549 if (t <= 0)
1550 return NULL;
1551
f872ec33 1552 sec = (time_t) (t / USEC_PER_SEC);
8b6c7120
LP
1553
1554 if (strftime(buf, l, "%a, %d %b %Y %H:%M:%S %z", localtime_r(&sec, &tm)) <= 0)
1555 return NULL;
1556
1557 return buf;
1558}
1559
871d7de4
LP
1560char *format_timespan(char *buf, size_t l, usec_t t) {
1561 static const struct {
1562 const char *suffix;
1563 usec_t usec;
1564 } table[] = {
1565 { "w", USEC_PER_WEEK },
1566 { "d", USEC_PER_DAY },
1567 { "h", USEC_PER_HOUR },
1568 { "min", USEC_PER_MINUTE },
1569 { "s", USEC_PER_SEC },
1570 { "ms", USEC_PER_MSEC },
1571 { "us", 1 },
1572 };
1573
1574 unsigned i;
1575 char *p = buf;
1576
1577 assert(buf);
1578 assert(l > 0);
1579
1580 if (t == (usec_t) -1)
1581 return NULL;
1582
1583 /* The result of this function can be parsed with parse_usec */
1584
1585 for (i = 0; i < ELEMENTSOF(table); i++) {
1586 int k;
1587 size_t n;
1588
1589 if (t < table[i].usec)
1590 continue;
1591
1592 if (l <= 1)
1593 break;
1594
1595 k = snprintf(p, l, "%s%llu%s", p > buf ? " " : "", (unsigned long long) (t / table[i].usec), table[i].suffix);
1596 n = MIN((size_t) k, l);
1597
1598 l -= n;
1599 p += n;
1600
1601 t %= table[i].usec;
1602 }
1603
1604 *p = 0;
1605
1606 return buf;
1607}
1608
42856c10
LP
1609bool fstype_is_network(const char *fstype) {
1610 static const char * const table[] = {
1611 "cifs",
1612 "smbfs",
1613 "ncpfs",
1614 "nfs",
ca139f94
LP
1615 "nfs4",
1616 "gfs",
1617 "gfs2"
42856c10
LP
1618 };
1619
1620 unsigned i;
1621
1622 for (i = 0; i < ELEMENTSOF(table); i++)
1623 if (streq(table[i], fstype))
1624 return true;
1625
1626 return false;
1627}
1628
601f6a1e
LP
1629int chvt(int vt) {
1630 int fd, r = 0;
1631
1632 if ((fd = open("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0)
1633 return -errno;
1634
1635 if (vt < 0) {
1636 int tiocl[2] = {
1637 TIOCL_GETKMSGREDIRECT,
1638 0
1639 };
1640
1641 if (ioctl(fd, TIOCLINUX, tiocl) < 0)
1642 return -errno;
1643
1644 vt = tiocl[0] <= 0 ? 1 : tiocl[0];
1645 }
1646
1647 if (ioctl(fd, VT_ACTIVATE, vt) < 0)
1648 r = -errno;
1649
a16e1123 1650 close_nointr_nofail(r);
601f6a1e
LP
1651 return r;
1652}
1653
80876c20
LP
1654int read_one_char(FILE *f, char *ret, bool *need_nl) {
1655 struct termios old_termios, new_termios;
1656 char c;
1657 char line[1024];
1658
1659 assert(f);
1660 assert(ret);
1661
1662 if (tcgetattr(fileno(f), &old_termios) >= 0) {
1663 new_termios = old_termios;
1664
1665 new_termios.c_lflag &= ~ICANON;
1666 new_termios.c_cc[VMIN] = 1;
1667 new_termios.c_cc[VTIME] = 0;
1668
1669 if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) {
1670 size_t k;
1671
1672 k = fread(&c, 1, 1, f);
1673
1674 tcsetattr(fileno(f), TCSADRAIN, &old_termios);
1675
1676 if (k <= 0)
1677 return -EIO;
1678
1679 if (need_nl)
1680 *need_nl = c != '\n';
1681
1682 *ret = c;
1683 return 0;
1684 }
1685 }
1686
1687 if (!(fgets(line, sizeof(line), f)))
1688 return -EIO;
1689
1690 truncate_nl(line);
1691
1692 if (strlen(line) != 1)
1693 return -EBADMSG;
1694
1695 if (need_nl)
1696 *need_nl = false;
1697
1698 *ret = line[0];
1699 return 0;
1700}
1701
1702int ask(char *ret, const char *replies, const char *text, ...) {
1703 assert(ret);
1704 assert(replies);
1705 assert(text);
1706
1707 for (;;) {
1708 va_list ap;
1709 char c;
1710 int r;
1711 bool need_nl = true;
1712
b1b2dc0c
LP
1713 fputs("\x1B[1m", stdout);
1714
80876c20
LP
1715 va_start(ap, text);
1716 vprintf(text, ap);
1717 va_end(ap);
1718
b1b2dc0c
LP
1719 fputs("\x1B[0m", stdout);
1720
80876c20
LP
1721 fflush(stdout);
1722
1723 if ((r = read_one_char(stdin, &c, &need_nl)) < 0) {
1724
1725 if (r == -EBADMSG) {
1726 puts("Bad input, please try again.");
1727 continue;
1728 }
1729
1730 putchar('\n');
1731 return r;
1732 }
1733
1734 if (need_nl)
1735 putchar('\n');
1736
1737 if (strchr(replies, c)) {
1738 *ret = c;
1739 return 0;
1740 }
1741
1742 puts("Read unexpected character, please try again.");
1743 }
1744}
1745
1746int reset_terminal(int fd) {
1747 struct termios termios;
1748 int r = 0;
1749
1750 assert(fd >= 0);
1751
aaf694ca 1752 /* Set terminal to some sane defaults */
80876c20
LP
1753
1754 if (tcgetattr(fd, &termios) < 0) {
1755 r = -errno;
1756 goto finish;
1757 }
1758
aaf694ca
LP
1759 /* We only reset the stuff that matters to the software. How
1760 * hardware is set up we don't touch assuming that somebody
1761 * else will do that for us */
1762
1763 termios.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | IUCLC);
80876c20
LP
1764 termios.c_iflag |= ICRNL | IMAXBEL | IUTF8;
1765 termios.c_oflag |= ONLCR;
1766 termios.c_cflag |= CREAD;
1767 termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOPRT | ECHOKE;
1768
1769 termios.c_cc[VINTR] = 03; /* ^C */
1770 termios.c_cc[VQUIT] = 034; /* ^\ */
1771 termios.c_cc[VERASE] = 0177;
1772 termios.c_cc[VKILL] = 025; /* ^X */
1773 termios.c_cc[VEOF] = 04; /* ^D */
1774 termios.c_cc[VSTART] = 021; /* ^Q */
1775 termios.c_cc[VSTOP] = 023; /* ^S */
1776 termios.c_cc[VSUSP] = 032; /* ^Z */
1777 termios.c_cc[VLNEXT] = 026; /* ^V */
1778 termios.c_cc[VWERASE] = 027; /* ^W */
1779 termios.c_cc[VREPRINT] = 022; /* ^R */
aaf694ca
LP
1780 termios.c_cc[VEOL] = 0;
1781 termios.c_cc[VEOL2] = 0;
80876c20
LP
1782
1783 termios.c_cc[VTIME] = 0;
1784 termios.c_cc[VMIN] = 1;
1785
1786 if (tcsetattr(fd, TCSANOW, &termios) < 0)
1787 r = -errno;
1788
1789finish:
1790 /* Just in case, flush all crap out */
1791 tcflush(fd, TCIOFLUSH);
1792
1793 return r;
1794}
1795
1796int open_terminal(const char *name, int mode) {
1797 int fd, r;
1798
1799 if ((fd = open(name, mode)) < 0)
1800 return -errno;
1801
1802 if ((r = isatty(fd)) < 0) {
1803 close_nointr_nofail(fd);
1804 return -errno;
1805 }
1806
1807 if (!r) {
1808 close_nointr_nofail(fd);
1809 return -ENOTTY;
1810 }
1811
1812 return fd;
1813}
1814
1815int flush_fd(int fd) {
1816 struct pollfd pollfd;
1817
1818 zero(pollfd);
1819 pollfd.fd = fd;
1820 pollfd.events = POLLIN;
1821
1822 for (;;) {
1823 char buf[1024];
1824 ssize_t l;
1825 int r;
1826
1827 if ((r = poll(&pollfd, 1, 0)) < 0) {
1828
1829 if (errno == EINTR)
1830 continue;
1831
1832 return -errno;
1833 }
1834
1835 if (r == 0)
1836 return 0;
1837
1838 if ((l = read(fd, buf, sizeof(buf))) < 0) {
1839
1840 if (errno == EINTR)
1841 continue;
1842
1843 if (errno == EAGAIN)
1844 return 0;
1845
1846 return -errno;
1847 }
1848
1849 if (l <= 0)
1850 return 0;
1851 }
1852}
1853
21de3988 1854int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocstty_eperm) {
bab45044 1855 int fd = -1, notify = -1, r, wd = -1;
80876c20
LP
1856
1857 assert(name);
1858
1859 /* We use inotify to be notified when the tty is closed. We
1860 * create the watch before checking if we can actually acquire
1861 * it, so that we don't lose any event.
1862 *
1863 * Note: strictly speaking this actually watches for the
1864 * device being closed, it does *not* really watch whether a
1865 * tty loses its controlling process. However, unless some
1866 * rogue process uses TIOCNOTTY on /dev/tty *after* closing
1867 * its tty otherwise this will not become a problem. As long
1868 * as the administrator makes sure not configure any service
1869 * on the same tty as an untrusted user this should not be a
1870 * problem. (Which he probably should not do anyway.) */
1871
1872 if (!fail && !force) {
1873 if ((notify = inotify_init1(IN_CLOEXEC)) < 0) {
1874 r = -errno;
1875 goto fail;
1876 }
1877
1878 if ((wd = inotify_add_watch(notify, name, IN_CLOSE)) < 0) {
1879 r = -errno;
1880 goto fail;
1881 }
1882 }
1883
1884 for (;;) {
e3d1855b
LP
1885 if (notify >= 0)
1886 if ((r = flush_fd(notify)) < 0)
1887 goto fail;
80876c20
LP
1888
1889 /* We pass here O_NOCTTY only so that we can check the return
1890 * value TIOCSCTTY and have a reliable way to figure out if we
1891 * successfully became the controlling process of the tty */
1892 if ((fd = open_terminal(name, O_RDWR|O_NOCTTY)) < 0)
1893 return -errno;
1894
1895 /* First, try to get the tty */
21de3988
LP
1896 r = ioctl(fd, TIOCSCTTY, force);
1897
1898 /* Sometimes it makes sense to ignore TIOCSCTTY
1899 * returning EPERM, i.e. when very likely we already
1900 * are have this controlling terminal. */
1901 if (r < 0 && errno == EPERM && ignore_tiocstty_eperm)
1902 r = 0;
1903
1904 if (r < 0 && (force || fail || errno != EPERM)) {
80876c20
LP
1905 r = -errno;
1906 goto fail;
1907 }
1908
1909 if (r >= 0)
1910 break;
1911
1912 assert(!fail);
1913 assert(!force);
1914 assert(notify >= 0);
1915
1916 for (;;) {
1917 struct inotify_event e;
1918 ssize_t l;
1919
1920 if ((l = read(notify, &e, sizeof(e))) != sizeof(e)) {
1921
1922 if (l < 0) {
1923
1924 if (errno == EINTR)
1925 continue;
1926
1927 r = -errno;
1928 } else
1929 r = -EIO;
1930
1931 goto fail;
1932 }
1933
1934 if (e.wd != wd || !(e.mask & IN_CLOSE)) {
1935 r = -errno;
1936 goto fail;
1937 }
1938
1939 break;
1940 }
1941
1942 /* We close the tty fd here since if the old session
1943 * ended our handle will be dead. It's important that
1944 * we do this after sleeping, so that we don't enter
1945 * an endless loop. */
1946 close_nointr_nofail(fd);
1947 }
1948
1949 if (notify >= 0)
a16e1123 1950 close_nointr_nofail(notify);
80876c20
LP
1951
1952 if ((r = reset_terminal(fd)) < 0)
1953 log_warning("Failed to reset terminal: %s", strerror(-r));
1954
1955 return fd;
1956
1957fail:
1958 if (fd >= 0)
a16e1123 1959 close_nointr_nofail(fd);
80876c20
LP
1960
1961 if (notify >= 0)
a16e1123 1962 close_nointr_nofail(notify);
80876c20
LP
1963
1964 return r;
1965}
1966
1967int release_terminal(void) {
1968 int r = 0, fd;
57cd2192 1969 struct sigaction sa_old, sa_new;
80876c20 1970
57cd2192 1971 if ((fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY)) < 0)
80876c20
LP
1972 return -errno;
1973
57cd2192
LP
1974 /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
1975 * by our own TIOCNOTTY */
1976
1977 zero(sa_new);
1978 sa_new.sa_handler = SIG_IGN;
1979 sa_new.sa_flags = SA_RESTART;
1980 assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
1981
80876c20
LP
1982 if (ioctl(fd, TIOCNOTTY) < 0)
1983 r = -errno;
1984
57cd2192
LP
1985 assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
1986
80876c20
LP
1987 close_nointr_nofail(fd);
1988 return r;
1989}
1990
9a34ec5f
LP
1991int sigaction_many(const struct sigaction *sa, ...) {
1992 va_list ap;
1993 int r = 0, sig;
1994
1995 va_start(ap, sa);
1996 while ((sig = va_arg(ap, int)) > 0)
1997 if (sigaction(sig, sa, NULL) < 0)
1998 r = -errno;
1999 va_end(ap);
2000
2001 return r;
2002}
2003
2004int ignore_signals(int sig, ...) {
a337c6fc 2005 struct sigaction sa;
9a34ec5f
LP
2006 va_list ap;
2007 int r = 0;
a337c6fc
LP
2008
2009 zero(sa);
2010 sa.sa_handler = SIG_IGN;
2011 sa.sa_flags = SA_RESTART;
2012
9a34ec5f
LP
2013 if (sigaction(sig, &sa, NULL) < 0)
2014 r = -errno;
2015
2016 va_start(ap, sig);
2017 while ((sig = va_arg(ap, int)) > 0)
2018 if (sigaction(sig, &sa, NULL) < 0)
2019 r = -errno;
2020 va_end(ap);
2021
2022 return r;
2023}
2024
2025int default_signals(int sig, ...) {
2026 struct sigaction sa;
2027 va_list ap;
2028 int r = 0;
2029
2030 zero(sa);
2031 sa.sa_handler = SIG_DFL;
2032 sa.sa_flags = SA_RESTART;
2033
2034 if (sigaction(sig, &sa, NULL) < 0)
2035 r = -errno;
2036
2037 va_start(ap, sig);
2038 while ((sig = va_arg(ap, int)) > 0)
2039 if (sigaction(sig, &sa, NULL) < 0)
2040 r = -errno;
2041 va_end(ap);
2042
2043 return r;
a337c6fc
LP
2044}
2045
8d567588
LP
2046int close_pipe(int p[]) {
2047 int a = 0, b = 0;
2048
2049 assert(p);
2050
2051 if (p[0] >= 0) {
2052 a = close_nointr(p[0]);
2053 p[0] = -1;
2054 }
2055
2056 if (p[1] >= 0) {
2057 b = close_nointr(p[1]);
2058 p[1] = -1;
2059 }
2060
2061 return a < 0 ? a : b;
2062}
2063
eb22ac37 2064ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
8d567588
LP
2065 uint8_t *p;
2066 ssize_t n = 0;
2067
2068 assert(fd >= 0);
2069 assert(buf);
2070
2071 p = buf;
2072
2073 while (nbytes > 0) {
2074 ssize_t k;
2075
2076 if ((k = read(fd, p, nbytes)) <= 0) {
2077
eb22ac37 2078 if (k < 0 && errno == EINTR)
8d567588
LP
2079 continue;
2080
eb22ac37 2081 if (k < 0 && errno == EAGAIN && do_poll) {
8d567588
LP
2082 struct pollfd pollfd;
2083
2084 zero(pollfd);
2085 pollfd.fd = fd;
2086 pollfd.events = POLLIN;
2087
2088 if (poll(&pollfd, 1, -1) < 0) {
2089 if (errno == EINTR)
2090 continue;
2091
2092 return n > 0 ? n : -errno;
2093 }
2094
2095 if (pollfd.revents != POLLIN)
2096 return n > 0 ? n : -EIO;
2097
2098 continue;
2099 }
2100
2101 return n > 0 ? n : (k < 0 ? -errno : 0);
2102 }
2103
2104 p += k;
2105 nbytes -= k;
2106 n += k;
2107 }
2108
2109 return n;
2110}
2111
eb22ac37
LP
2112ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
2113 const uint8_t *p;
2114 ssize_t n = 0;
2115
2116 assert(fd >= 0);
2117 assert(buf);
2118
2119 p = buf;
2120
2121 while (nbytes > 0) {
2122 ssize_t k;
2123
2124 if ((k = write(fd, p, nbytes)) <= 0) {
2125
2126 if (k < 0 && errno == EINTR)
2127 continue;
2128
2129 if (k < 0 && errno == EAGAIN && do_poll) {
2130 struct pollfd pollfd;
2131
2132 zero(pollfd);
2133 pollfd.fd = fd;
2134 pollfd.events = POLLOUT;
2135
2136 if (poll(&pollfd, 1, -1) < 0) {
2137 if (errno == EINTR)
2138 continue;
2139
2140 return n > 0 ? n : -errno;
2141 }
2142
2143 if (pollfd.revents != POLLOUT)
2144 return n > 0 ? n : -EIO;
2145
2146 continue;
2147 }
2148
2149 return n > 0 ? n : (k < 0 ? -errno : 0);
2150 }
2151
2152 p += k;
2153 nbytes -= k;
2154 n += k;
2155 }
2156
2157 return n;
2158}
2159
8d567588
LP
2160int path_is_mount_point(const char *t) {
2161 struct stat a, b;
2162 char *copy;
2163
2164 if (lstat(t, &a) < 0) {
2165
2166 if (errno == ENOENT)
2167 return 0;
2168
2169 return -errno;
2170 }
2171
2172 if (!(copy = strdup(t)))
2173 return -ENOMEM;
2174
2175 if (lstat(dirname(copy), &b) < 0) {
2176 free(copy);
2177 return -errno;
2178 }
2179
2180 free(copy);
2181
2182 return a.st_dev != b.st_dev;
2183}
2184
24a6e4a4
LP
2185int parse_usec(const char *t, usec_t *usec) {
2186 static const struct {
2187 const char *suffix;
2188 usec_t usec;
2189 } table[] = {
2190 { "sec", USEC_PER_SEC },
2191 { "s", USEC_PER_SEC },
2192 { "min", USEC_PER_MINUTE },
2193 { "hr", USEC_PER_HOUR },
2194 { "h", USEC_PER_HOUR },
2195 { "d", USEC_PER_DAY },
2196 { "w", USEC_PER_WEEK },
2197 { "msec", USEC_PER_MSEC },
2198 { "ms", USEC_PER_MSEC },
2199 { "m", USEC_PER_MINUTE },
2200 { "usec", 1ULL },
2201 { "us", 1ULL },
2202 { "", USEC_PER_SEC },
2203 };
2204
2205 const char *p;
2206 usec_t r = 0;
2207
2208 assert(t);
2209 assert(usec);
2210
2211 p = t;
2212 do {
2213 long long l;
2214 char *e;
2215 unsigned i;
2216
2217 errno = 0;
2218 l = strtoll(p, &e, 10);
2219
2220 if (errno != 0)
2221 return -errno;
2222
2223 if (l < 0)
2224 return -ERANGE;
2225
2226 if (e == p)
2227 return -EINVAL;
2228
2229 e += strspn(e, WHITESPACE);
2230
2231 for (i = 0; i < ELEMENTSOF(table); i++)
2232 if (startswith(e, table[i].suffix)) {
2233 r += (usec_t) l * table[i].usec;
2234 p = e + strlen(table[i].suffix);
2235 break;
2236 }
2237
2238 if (i >= ELEMENTSOF(table))
2239 return -EINVAL;
2240
2241 } while (*p != 0);
2242
2243 *usec = r;
2244
2245 return 0;
2246}
2247
843d2643
LP
2248int make_stdio(int fd) {
2249 int r, s, t;
2250
2251 assert(fd >= 0);
2252
2253 r = dup2(fd, STDIN_FILENO);
2254 s = dup2(fd, STDOUT_FILENO);
2255 t = dup2(fd, STDERR_FILENO);
2256
2257 if (fd >= 3)
2258 close_nointr_nofail(fd);
2259
2260 if (r < 0 || s < 0 || t < 0)
2261 return -errno;
2262
2263 return 0;
2264}
2265
cb8a8f78
LP
2266bool is_clean_exit(int code, int status) {
2267
2268 if (code == CLD_EXITED)
2269 return status == 0;
2270
2271 /* If a daemon does not implement handlers for some of the
2272 * signals that's not considered an unclean shutdown */
2273 if (code == CLD_KILLED)
2274 return
2275 status == SIGHUP ||
2276 status == SIGINT ||
2277 status == SIGTERM ||
2278 status == SIGPIPE;
2279
2280 return false;
2281}
2282
8407a5d0
LP
2283bool is_device_path(const char *path) {
2284
2285 /* Returns true on paths that refer to a device, either in
2286 * sysfs or in /dev */
2287
2288 return
2289 path_startswith(path, "/dev/") ||
2290 path_startswith(path, "/sys/");
2291}
2292
01f78473
LP
2293int dir_is_empty(const char *path) {
2294 DIR *d;
2295 int r;
2296 struct dirent buf, *de;
2297
2298 if (!(d = opendir(path)))
2299 return -errno;
2300
2301 for (;;) {
2302 if ((r = readdir_r(d, &buf, &de)) > 0) {
2303 r = -r;
2304 break;
2305 }
2306
2307 if (!de) {
2308 r = 1;
2309 break;
2310 }
2311
2312 if (!ignore_file(de->d_name)) {
2313 r = 0;
2314 break;
2315 }
2316 }
2317
2318 closedir(d);
2319 return r;
2320}
2321
d3782d60
LP
2322unsigned long long random_ull(void) {
2323 int fd;
2324 uint64_t ull;
2325 ssize_t r;
2326
2327 if ((fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY)) < 0)
2328 goto fallback;
2329
eb22ac37 2330 r = loop_read(fd, &ull, sizeof(ull), true);
d3782d60
LP
2331 close_nointr_nofail(fd);
2332
2333 if (r != sizeof(ull))
2334 goto fallback;
2335
2336 return ull;
2337
2338fallback:
2339 return random() * RAND_MAX + random();
2340}
2341
5b6319dc
LP
2342void rename_process(const char name[8]) {
2343 assert(name);
2344
2345 prctl(PR_SET_NAME, name);
2346
2347 /* This is a like a poor man's setproctitle(). The string
2348 * passed should fit in 7 chars (i.e. the length of
2349 * "systemd") */
2350
2351 if (program_invocation_name)
2352 strncpy(program_invocation_name, name, strlen(program_invocation_name));
2353}
2354
7d793605
LP
2355void sigset_add_many(sigset_t *ss, ...) {
2356 va_list ap;
2357 int sig;
2358
2359 assert(ss);
2360
2361 va_start(ap, ss);
2362 while ((sig = va_arg(ap, int)) > 0)
2363 assert_se(sigaddset(ss, sig) == 0);
2364 va_end(ap);
2365}
2366
ef2f1067
LP
2367char* gethostname_malloc(void) {
2368 struct utsname u;
2369
2370 assert_se(uname(&u) >= 0);
2371
2372 if (u.nodename[0])
2373 return strdup(u.nodename);
2374
2375 return strdup(u.sysname);
2376}
2377
8c6db833
LP
2378int getmachineid_malloc(char **b) {
2379 int r;
2380
2381 assert(b);
2382
2383 if ((r = read_one_line_file("/var/lib/dbus/machine-id", b)) < 0)
2384 return r;
2385
2386 strstrip(*b);
2387 return 0;
2388}
2389
ef2f1067
LP
2390char* getlogname_malloc(void) {
2391 uid_t uid;
2392 long bufsize;
2393 char *buf, *name;
2394 struct passwd pwbuf, *pw = NULL;
2395 struct stat st;
2396
2397 if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0)
2398 uid = st.st_uid;
2399 else
2400 uid = getuid();
2401
2402 /* Shortcut things to avoid NSS lookups */
2403 if (uid == 0)
2404 return strdup("root");
2405
2406 if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) <= 0)
2407 bufsize = 4096;
2408
2409 if (!(buf = malloc(bufsize)))
2410 return NULL;
2411
2412 if (getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0 && pw) {
2413 name = strdup(pw->pw_name);
2414 free(buf);
2415 return name;
2416 }
2417
2418 free(buf);
2419
2420 if (asprintf(&name, "%lu", (unsigned long) uid) < 0)
2421 return NULL;
2422
2423 return name;
2424}
2425
8c6db833
LP
2426int getttyname_malloc(char **r) {
2427 char path[PATH_MAX], *p, *c;
2428
2429 assert(r);
ef2f1067
LP
2430
2431 if (ttyname_r(STDIN_FILENO, path, sizeof(path)) < 0)
8c6db833 2432 return -errno;
ef2f1067
LP
2433
2434 char_array_0(path);
2435
2436 p = path;
2437 if (startswith(path, "/dev/"))
2438 p += 5;
2439
8c6db833
LP
2440 if (!(c = strdup(p)))
2441 return -ENOMEM;
2442
2443 *r = c;
2444 return 0;
2445}
2446
2447static int rm_rf_children(int fd, bool only_dirs) {
2448 DIR *d;
2449 int ret = 0;
2450
2451 assert(fd >= 0);
2452
2453 /* This returns the first error we run into, but nevertheless
2454 * tries to go on */
2455
2456 if (!(d = fdopendir(fd))) {
2457 close_nointr_nofail(fd);
2458 return -errno;
2459 }
2460
2461 for (;;) {
2462 struct dirent buf, *de;
2463 bool is_dir;
2464 int r;
2465
2466 if ((r = readdir_r(d, &buf, &de)) != 0) {
2467 if (ret == 0)
2468 ret = -r;
2469 break;
2470 }
2471
2472 if (!de)
2473 break;
2474
2475 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
2476 continue;
2477
2478 if (de->d_type == DT_UNKNOWN) {
2479 struct stat st;
2480
2481 if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2482 if (ret == 0)
2483 ret = -errno;
2484 continue;
2485 }
2486
2487 is_dir = S_ISDIR(st.st_mode);
2488 } else
2489 is_dir = de->d_type == DT_DIR;
2490
2491 if (is_dir) {
2492 int subdir_fd;
2493
2494 if ((subdir_fd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)) < 0) {
2495 if (ret == 0)
2496 ret = -errno;
2497 continue;
2498 }
2499
2500 if ((r = rm_rf_children(subdir_fd, only_dirs)) < 0) {
2501 if (ret == 0)
2502 ret = r;
2503 }
2504
2505 if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
2506 if (ret == 0)
2507 ret = -errno;
2508 }
2509 } else if (!only_dirs) {
2510
2511 if (unlinkat(fd, de->d_name, 0) < 0) {
2512 if (ret == 0)
2513 ret = -errno;
2514 }
2515 }
2516 }
2517
2518 closedir(d);
2519
2520 return ret;
2521}
2522
2523int rm_rf(const char *path, bool only_dirs, bool delete_root) {
2524 int fd;
2525 int r;
2526
2527 assert(path);
2528
2529 if ((fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)) < 0) {
2530
2531 if (errno != ENOTDIR)
2532 return -errno;
2533
2534 if (delete_root && !only_dirs)
2535 if (unlink(path) < 0)
2536 return -errno;
2537
2538 return 0;
2539 }
2540
2541 r = rm_rf_children(fd, only_dirs);
2542
2543 if (delete_root)
2544 if (rmdir(path) < 0) {
2545 if (r == 0)
2546 r = -errno;
2547 }
2548
2549 return r;
2550}
2551
2552int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
2553 assert(path);
2554
2555 /* Under the assumption that we are running privileged we
2556 * first change the access mode and only then hand out
2557 * ownership to avoid a window where access is too open. */
2558
2559 if (chmod(path, mode) < 0)
2560 return -errno;
2561
2562 if (chown(path, uid, gid) < 0)
2563 return -errno;
2564
2565 return 0;
ef2f1067
LP
2566}
2567
82c121a4
LP
2568cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
2569 cpu_set_t *r;
2570 unsigned n = 1024;
2571
2572 /* Allocates the cpuset in the right size */
2573
2574 for (;;) {
2575 if (!(r = CPU_ALLOC(n)))
2576 return NULL;
2577
2578 if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), r) >= 0) {
2579 CPU_ZERO_S(CPU_ALLOC_SIZE(n), r);
2580
2581 if (ncpus)
2582 *ncpus = n;
2583
2584 return r;
2585 }
2586
2587 CPU_FREE(r);
2588
2589 if (errno != EINVAL)
2590 return NULL;
2591
2592 n *= 2;
2593 }
2594}
2595
9e58ff9c
LP
2596void status_vprintf(const char *format, va_list ap) {
2597 char *s = NULL;
2598 int fd = -1;
2599
2600 assert(format);
2601
2602 /* This independent of logging, as status messages are
2603 * optional and go exclusively to the console. */
2604
2605 if (vasprintf(&s, format, ap) < 0)
2606 goto finish;
2607
2608 if ((fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0)
2609 goto finish;
2610
2611 write(fd, s, strlen(s));
2612
2613finish:
2614 free(s);
2615
2616 if (fd >= 0)
2617 close_nointr_nofail(fd);
2618}
2619
c846ff47
LP
2620void status_printf(const char *format, ...) {
2621 va_list ap;
2622
2623 assert(format);
2624
2625 va_start(ap, format);
2626 status_vprintf(format, ap);
2627 va_end(ap);
2628}
2629
2630void status_welcome(void) {
2631
2632#if defined(TARGET_FEDORA)
2633 char *r;
2634
2635 if (read_one_line_file("/etc/system-release", &r) < 0)
2636 return;
2637
2638 truncate_nl(r);
2639
2640 /* This tries to mimic the color magic the old Red Hat sysinit
2641 * script did. */
2642
2643 if (startswith(r, "Red Hat"))
2e54424d 2644 status_printf("Welcome to \x1B[0;31m%s\x1B[0m!\n", r); /* Red for RHEL */
c846ff47 2645 else if (startswith(r, "Fedora"))
2e54424d 2646 status_printf("Welcome to \x1B[0;34m%s\x1B[0m!\n", r); /* Blue for Fedora */
c846ff47 2647 else
2e54424d 2648 status_printf("Welcome to %s!\n", r);
c846ff47
LP
2649
2650 free(r);
2651
2652#elif defined(TARGET_SUSE)
2653 char *r;
2654
2655 if (read_one_line_file("/etc/SuSE-release", &r) < 0)
2656 return;
2657
2658 truncate_nl(r);
2659
2e54424d 2660 status_printf("Welcome to \x1B[0;32m%s\x1B[0m!\n", r); /* Green for SUSE */
c846ff47
LP
2661 free(r);
2662#else
2663#warning "You probably should add a welcome text logic here."
2664#endif
2665}
2666
1dccbe19
LP
2667static const char *const ioprio_class_table[] = {
2668 [IOPRIO_CLASS_NONE] = "none",
2669 [IOPRIO_CLASS_RT] = "realtime",
2670 [IOPRIO_CLASS_BE] = "best-effort",
2671 [IOPRIO_CLASS_IDLE] = "idle"
2672};
2673
2674DEFINE_STRING_TABLE_LOOKUP(ioprio_class, int);
2675
2676static const char *const sigchld_code_table[] = {
2677 [CLD_EXITED] = "exited",
2678 [CLD_KILLED] = "killed",
2679 [CLD_DUMPED] = "dumped",
2680 [CLD_TRAPPED] = "trapped",
2681 [CLD_STOPPED] = "stopped",
2682 [CLD_CONTINUED] = "continued",
2683};
2684
2685DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
2686
2687static const char *const log_facility_table[LOG_NFACILITIES] = {
2688 [LOG_FAC(LOG_KERN)] = "kern",
2689 [LOG_FAC(LOG_USER)] = "user",
2690 [LOG_FAC(LOG_MAIL)] = "mail",
2691 [LOG_FAC(LOG_DAEMON)] = "daemon",
2692 [LOG_FAC(LOG_AUTH)] = "auth",
2693 [LOG_FAC(LOG_SYSLOG)] = "syslog",
2694 [LOG_FAC(LOG_LPR)] = "lpr",
2695 [LOG_FAC(LOG_NEWS)] = "news",
2696 [LOG_FAC(LOG_UUCP)] = "uucp",
2697 [LOG_FAC(LOG_CRON)] = "cron",
2698 [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
2699 [LOG_FAC(LOG_FTP)] = "ftp",
2700 [LOG_FAC(LOG_LOCAL0)] = "local0",
2701 [LOG_FAC(LOG_LOCAL1)] = "local1",
2702 [LOG_FAC(LOG_LOCAL2)] = "local2",
2703 [LOG_FAC(LOG_LOCAL3)] = "local3",
2704 [LOG_FAC(LOG_LOCAL4)] = "local4",
2705 [LOG_FAC(LOG_LOCAL5)] = "local5",
2706 [LOG_FAC(LOG_LOCAL6)] = "local6",
2707 [LOG_FAC(LOG_LOCAL7)] = "local7"
2708};
2709
2710DEFINE_STRING_TABLE_LOOKUP(log_facility, int);
2711
2712static const char *const log_level_table[] = {
2713 [LOG_EMERG] = "emerg",
2714 [LOG_ALERT] = "alert",
2715 [LOG_CRIT] = "crit",
2716 [LOG_ERR] = "err",
2717 [LOG_WARNING] = "warning",
2718 [LOG_NOTICE] = "notice",
2719 [LOG_INFO] = "info",
2720 [LOG_DEBUG] = "debug"
2721};
2722
2723DEFINE_STRING_TABLE_LOOKUP(log_level, int);
2724
2725static const char* const sched_policy_table[] = {
2726 [SCHED_OTHER] = "other",
2727 [SCHED_BATCH] = "batch",
2728 [SCHED_IDLE] = "idle",
2729 [SCHED_FIFO] = "fifo",
2730 [SCHED_RR] = "rr"
2731};
2732
2733DEFINE_STRING_TABLE_LOOKUP(sched_policy, int);
2734
2735static const char* const rlimit_table[] = {
2736 [RLIMIT_CPU] = "LimitCPU",
2737 [RLIMIT_FSIZE] = "LimitFSIZE",
2738 [RLIMIT_DATA] = "LimitDATA",
2739 [RLIMIT_STACK] = "LimitSTACK",
2740 [RLIMIT_CORE] = "LimitCORE",
2741 [RLIMIT_RSS] = "LimitRSS",
2742 [RLIMIT_NOFILE] = "LimitNOFILE",
2743 [RLIMIT_AS] = "LimitAS",
2744 [RLIMIT_NPROC] = "LimitNPROC",
2745 [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
2746 [RLIMIT_LOCKS] = "LimitLOCKS",
2747 [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
2748 [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
2749 [RLIMIT_NICE] = "LimitNICE",
2750 [RLIMIT_RTPRIO] = "LimitRTPRIO",
2751 [RLIMIT_RTTIME] = "LimitRTTIME"
2752};
2753
2754DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
4fd5948e
LP
2755
2756static const char* const ip_tos_table[] = {
2757 [IPTOS_LOWDELAY] = "low-delay",
2758 [IPTOS_THROUGHPUT] = "throughput",
2759 [IPTOS_RELIABILITY] = "reliability",
2760 [IPTOS_LOWCOST] = "low-cost",
2761};
2762
2763DEFINE_STRING_TABLE_LOOKUP(ip_tos, int);