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