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