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