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