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