]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/util.c
man: fix man page chapter in Makefile.am
[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
87d2c1ff 1086 r = join("[", 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
bab45044 2388 int fd = -1, notify = -1, r, wd = -1;
af6da548 2389 usec_t ts = 0;
80876c20
LP
2390
2391 assert(name);
2392
2393 /* We use inotify to be notified when the tty is closed. We
2394 * create the watch before checking if we can actually acquire
2395 * it, so that we don't lose any event.
2396 *
2397 * Note: strictly speaking this actually watches for the
2398 * device being closed, it does *not* really watch whether a
2399 * tty loses its controlling process. However, unless some
2400 * rogue process uses TIOCNOTTY on /dev/tty *after* closing
2401 * its tty otherwise this will not become a problem. As long
2402 * as the administrator makes sure not configure any service
2403 * on the same tty as an untrusted user this should not be a
2404 * problem. (Which he probably should not do anyway.) */
2405
af6da548
LP
2406 if (timeout != (usec_t) -1)
2407 ts = now(CLOCK_MONOTONIC);
2408
80876c20 2409 if (!fail && !force) {
af6da548
LP
2410 notify = inotify_init1(IN_CLOEXEC | (timeout != (usec_t) -1 ? IN_NONBLOCK : 0));
2411 if (notify < 0) {
80876c20
LP
2412 r = -errno;
2413 goto fail;
2414 }
2415
af6da548
LP
2416 wd = inotify_add_watch(notify, name, IN_CLOSE);
2417 if (wd < 0) {
80876c20
LP
2418 r = -errno;
2419 goto fail;
2420 }
2421 }
2422
2423 for (;;) {
af6da548
LP
2424 if (notify >= 0) {
2425 r = flush_fd(notify);
2426 if (r < 0)
e3d1855b 2427 goto fail;
af6da548 2428 }
80876c20
LP
2429
2430 /* We pass here O_NOCTTY only so that we can check the return
2431 * value TIOCSCTTY and have a reliable way to figure out if we
2432 * successfully became the controlling process of the tty */
af6da548
LP
2433 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
2434 if (fd < 0)
6ea832a2 2435 return fd;
80876c20
LP
2436
2437 /* First, try to get the tty */
21de3988
LP
2438 r = ioctl(fd, TIOCSCTTY, force);
2439
2440 /* Sometimes it makes sense to ignore TIOCSCTTY
2441 * returning EPERM, i.e. when very likely we already
2442 * are have this controlling terminal. */
2443 if (r < 0 && errno == EPERM && ignore_tiocstty_eperm)
2444 r = 0;
2445
2446 if (r < 0 && (force || fail || errno != EPERM)) {
80876c20
LP
2447 r = -errno;
2448 goto fail;
2449 }
2450
2451 if (r >= 0)
2452 break;
2453
2454 assert(!fail);
2455 assert(!force);
2456 assert(notify >= 0);
2457
2458 for (;;) {
f601daa7 2459 uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX];
80876c20 2460 ssize_t l;
f601daa7 2461 struct inotify_event *e;
80876c20 2462
af6da548
LP
2463 if (timeout != (usec_t) -1) {
2464 usec_t n;
2465
2466 n = now(CLOCK_MONOTONIC);
2467 if (ts + timeout < n) {
2468 r = -ETIMEDOUT;
2469 goto fail;
2470 }
2471
2472 r = fd_wait_for_event(fd, POLLIN, ts + timeout - n);
2473 if (r < 0)
2474 goto fail;
2475
2476 if (r == 0) {
2477 r = -ETIMEDOUT;
2478 goto fail;
2479 }
2480 }
2481
2482 l = read(notify, inotify_buffer, sizeof(inotify_buffer));
2483 if (l < 0) {
80876c20 2484
af6da548 2485 if (errno == EINTR || errno == EAGAIN)
f601daa7
LP
2486 continue;
2487
2488 r = -errno;
2489 goto fail;
2490 }
2491
2492 e = (struct inotify_event*) inotify_buffer;
80876c20 2493
f601daa7
LP
2494 while (l > 0) {
2495 size_t step;
80876c20 2496
f601daa7 2497 if (e->wd != wd || !(e->mask & IN_CLOSE)) {
80876c20 2498 r = -EIO;
f601daa7
LP
2499 goto fail;
2500 }
80876c20 2501
f601daa7
LP
2502 step = sizeof(struct inotify_event) + e->len;
2503 assert(step <= (size_t) l);
80876c20 2504
f601daa7
LP
2505 e = (struct inotify_event*) ((uint8_t*) e + step);
2506 l -= step;
80876c20
LP
2507 }
2508
2509 break;
2510 }
2511
2512 /* We close the tty fd here since if the old session
2513 * ended our handle will be dead. It's important that
2514 * we do this after sleeping, so that we don't enter
2515 * an endless loop. */
2516 close_nointr_nofail(fd);
2517 }
2518
2519 if (notify >= 0)
a16e1123 2520 close_nointr_nofail(notify);
80876c20 2521
512947d4
MS
2522 r = reset_terminal_fd(fd, true);
2523 if (r < 0)
80876c20
LP
2524 log_warning("Failed to reset terminal: %s", strerror(-r));
2525
2526 return fd;
2527
2528fail:
2529 if (fd >= 0)
a16e1123 2530 close_nointr_nofail(fd);
80876c20
LP
2531
2532 if (notify >= 0)
a16e1123 2533 close_nointr_nofail(notify);
80876c20
LP
2534
2535 return r;
2536}
2537
2538int release_terminal(void) {
2539 int r = 0, fd;
57cd2192 2540 struct sigaction sa_old, sa_new;
80876c20 2541
ccaa6149 2542 if ((fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY|O_CLOEXEC)) < 0)
80876c20
LP
2543 return -errno;
2544
57cd2192
LP
2545 /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
2546 * by our own TIOCNOTTY */
2547
2548 zero(sa_new);
2549 sa_new.sa_handler = SIG_IGN;
2550 sa_new.sa_flags = SA_RESTART;
2551 assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
2552
80876c20
LP
2553 if (ioctl(fd, TIOCNOTTY) < 0)
2554 r = -errno;
2555
57cd2192
LP
2556 assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
2557
80876c20
LP
2558 close_nointr_nofail(fd);
2559 return r;
2560}
2561
9a34ec5f
LP
2562int sigaction_many(const struct sigaction *sa, ...) {
2563 va_list ap;
2564 int r = 0, sig;
2565
2566 va_start(ap, sa);
2567 while ((sig = va_arg(ap, int)) > 0)
2568 if (sigaction(sig, sa, NULL) < 0)
2569 r = -errno;
2570 va_end(ap);
2571
2572 return r;
2573}
2574
2575int ignore_signals(int sig, ...) {
a337c6fc 2576 struct sigaction sa;
9a34ec5f
LP
2577 va_list ap;
2578 int r = 0;
a337c6fc
LP
2579
2580 zero(sa);
2581 sa.sa_handler = SIG_IGN;
2582 sa.sa_flags = SA_RESTART;
2583
9a34ec5f
LP
2584 if (sigaction(sig, &sa, NULL) < 0)
2585 r = -errno;
2586
2587 va_start(ap, sig);
2588 while ((sig = va_arg(ap, int)) > 0)
2589 if (sigaction(sig, &sa, NULL) < 0)
2590 r = -errno;
2591 va_end(ap);
2592
2593 return r;
2594}
2595
2596int default_signals(int sig, ...) {
2597 struct sigaction sa;
2598 va_list ap;
2599 int r = 0;
2600
2601 zero(sa);
2602 sa.sa_handler = SIG_DFL;
2603 sa.sa_flags = SA_RESTART;
2604
2605 if (sigaction(sig, &sa, NULL) < 0)
2606 r = -errno;
2607
2608 va_start(ap, sig);
2609 while ((sig = va_arg(ap, int)) > 0)
2610 if (sigaction(sig, &sa, NULL) < 0)
2611 r = -errno;
2612 va_end(ap);
2613
2614 return r;
a337c6fc
LP
2615}
2616
8d567588
LP
2617int close_pipe(int p[]) {
2618 int a = 0, b = 0;
2619
2620 assert(p);
2621
2622 if (p[0] >= 0) {
2623 a = close_nointr(p[0]);
2624 p[0] = -1;
2625 }
2626
2627 if (p[1] >= 0) {
2628 b = close_nointr(p[1]);
2629 p[1] = -1;
2630 }
2631
2632 return a < 0 ? a : b;
2633}
2634
eb22ac37 2635ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
8d567588
LP
2636 uint8_t *p;
2637 ssize_t n = 0;
2638
2639 assert(fd >= 0);
2640 assert(buf);
2641
2642 p = buf;
2643
2644 while (nbytes > 0) {
2645 ssize_t k;
2646
2647 if ((k = read(fd, p, nbytes)) <= 0) {
2648
eb22ac37 2649 if (k < 0 && errno == EINTR)
8d567588
LP
2650 continue;
2651
eb22ac37 2652 if (k < 0 && errno == EAGAIN && do_poll) {
8d567588
LP
2653 struct pollfd pollfd;
2654
2655 zero(pollfd);
2656 pollfd.fd = fd;
2657 pollfd.events = POLLIN;
2658
2659 if (poll(&pollfd, 1, -1) < 0) {
2660 if (errno == EINTR)
2661 continue;
2662
2663 return n > 0 ? n : -errno;
2664 }
2665
2666 if (pollfd.revents != POLLIN)
2667 return n > 0 ? n : -EIO;
2668
2669 continue;
2670 }
2671
2672 return n > 0 ? n : (k < 0 ? -errno : 0);
2673 }
2674
2675 p += k;
2676 nbytes -= k;
2677 n += k;
2678 }
2679
2680 return n;
2681}
2682
eb22ac37
LP
2683ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
2684 const uint8_t *p;
2685 ssize_t n = 0;
2686
2687 assert(fd >= 0);
2688 assert(buf);
2689
2690 p = buf;
2691
2692 while (nbytes > 0) {
2693 ssize_t k;
2694
fe652127
LP
2695 k = write(fd, p, nbytes);
2696 if (k <= 0) {
eb22ac37
LP
2697
2698 if (k < 0 && errno == EINTR)
2699 continue;
2700
2701 if (k < 0 && errno == EAGAIN && do_poll) {
2702 struct pollfd pollfd;
2703
2704 zero(pollfd);
2705 pollfd.fd = fd;
2706 pollfd.events = POLLOUT;
2707
2708 if (poll(&pollfd, 1, -1) < 0) {
2709 if (errno == EINTR)
2710 continue;
2711
2712 return n > 0 ? n : -errno;
2713 }
2714
2715 if (pollfd.revents != POLLOUT)
2716 return n > 0 ? n : -EIO;
2717
2718 continue;
2719 }
2720
2721 return n > 0 ? n : (k < 0 ? -errno : 0);
2722 }
2723
2724 p += k;
2725 nbytes -= k;
2726 n += k;
2727 }
2728
2729 return n;
2730}
2731
24a6e4a4
LP
2732int parse_usec(const char *t, usec_t *usec) {
2733 static const struct {
2734 const char *suffix;
2735 usec_t usec;
2736 } table[] = {
2737 { "sec", USEC_PER_SEC },
2738 { "s", USEC_PER_SEC },
2739 { "min", USEC_PER_MINUTE },
2740 { "hr", USEC_PER_HOUR },
2741 { "h", USEC_PER_HOUR },
2742 { "d", USEC_PER_DAY },
2743 { "w", USEC_PER_WEEK },
2744 { "msec", USEC_PER_MSEC },
2745 { "ms", USEC_PER_MSEC },
2746 { "m", USEC_PER_MINUTE },
2747 { "usec", 1ULL },
2748 { "us", 1ULL },
d88a251b 2749 { "", USEC_PER_SEC }, /* default is sec */
24a6e4a4
LP
2750 };
2751
2752 const char *p;
2753 usec_t r = 0;
2754
2755 assert(t);
2756 assert(usec);
2757
2758 p = t;
2759 do {
2760 long long l;
2761 char *e;
2762 unsigned i;
2763
2764 errno = 0;
2765 l = strtoll(p, &e, 10);
2766
2767 if (errno != 0)
2768 return -errno;
2769
2770 if (l < 0)
2771 return -ERANGE;
2772
2773 if (e == p)
2774 return -EINVAL;
2775
2776 e += strspn(e, WHITESPACE);
2777
2778 for (i = 0; i < ELEMENTSOF(table); i++)
2779 if (startswith(e, table[i].suffix)) {
2780 r += (usec_t) l * table[i].usec;
2781 p = e + strlen(table[i].suffix);
2782 break;
2783 }
2784
2785 if (i >= ELEMENTSOF(table))
2786 return -EINVAL;
2787
2788 } while (*p != 0);
2789
2790 *usec = r;
2791
2792 return 0;
2793}
2794
d88a251b
LP
2795int parse_nsec(const char *t, nsec_t *nsec) {
2796 static const struct {
2797 const char *suffix;
2798 nsec_t nsec;
2799 } table[] = {
2800 { "sec", NSEC_PER_SEC },
2801 { "s", NSEC_PER_SEC },
2802 { "min", NSEC_PER_MINUTE },
2803 { "hr", NSEC_PER_HOUR },
2804 { "h", NSEC_PER_HOUR },
2805 { "d", NSEC_PER_DAY },
2806 { "w", NSEC_PER_WEEK },
2807 { "msec", NSEC_PER_MSEC },
2808 { "ms", NSEC_PER_MSEC },
2809 { "m", NSEC_PER_MINUTE },
2810 { "usec", NSEC_PER_USEC },
2811 { "us", NSEC_PER_USEC },
2812 { "nsec", 1ULL },
2813 { "ns", 1ULL },
2814 { "", 1ULL }, /* default is nsec */
2815 };
2816
2817 const char *p;
2818 nsec_t r = 0;
2819
2820 assert(t);
2821 assert(nsec);
2822
2823 p = t;
2824 do {
2825 long long l;
2826 char *e;
2827 unsigned i;
2828
2829 errno = 0;
2830 l = strtoll(p, &e, 10);
2831
2832 if (errno != 0)
2833 return -errno;
2834
2835 if (l < 0)
2836 return -ERANGE;
2837
2838 if (e == p)
2839 return -EINVAL;
2840
2841 e += strspn(e, WHITESPACE);
2842
2843 for (i = 0; i < ELEMENTSOF(table); i++)
2844 if (startswith(e, table[i].suffix)) {
2845 r += (nsec_t) l * table[i].nsec;
2846 p = e + strlen(table[i].suffix);
2847 break;
2848 }
2849
2850 if (i >= ELEMENTSOF(table))
2851 return -EINVAL;
2852
2853 } while (*p != 0);
2854
2855 *nsec = r;
2856
2857 return 0;
2858}
2859
ab1f0633
LP
2860int parse_bytes(const char *t, off_t *bytes) {
2861 static const struct {
2862 const char *suffix;
2863 off_t factor;
2864 } table[] = {
2865 { "B", 1 },
2866 { "K", 1024ULL },
2867 { "M", 1024ULL*1024ULL },
2868 { "G", 1024ULL*1024ULL*1024ULL },
2869 { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
32895bb3
LP
2870 { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
2871 { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
ab1f0633
LP
2872 { "", 1 },
2873 };
2874
2875 const char *p;
2876 off_t r = 0;
2877
2878 assert(t);
2879 assert(bytes);
2880
2881 p = t;
2882 do {
2883 long long l;
2884 char *e;
2885 unsigned i;
2886
2887 errno = 0;
2888 l = strtoll(p, &e, 10);
2889
2890 if (errno != 0)
2891 return -errno;
2892
2893 if (l < 0)
2894 return -ERANGE;
2895
2896 if (e == p)
2897 return -EINVAL;
2898
2899 e += strspn(e, WHITESPACE);
2900
2901 for (i = 0; i < ELEMENTSOF(table); i++)
2902 if (startswith(e, table[i].suffix)) {
2903 r += (off_t) l * table[i].factor;
2904 p = e + strlen(table[i].suffix);
2905 break;
2906 }
2907
2908 if (i >= ELEMENTSOF(table))
2909 return -EINVAL;
2910
2911 } while (*p != 0);
2912
2913 *bytes = r;
2914
2915 return 0;
2916}
2917
843d2643
LP
2918int make_stdio(int fd) {
2919 int r, s, t;
2920
2921 assert(fd >= 0);
2922
2923 r = dup2(fd, STDIN_FILENO);
2924 s = dup2(fd, STDOUT_FILENO);
2925 t = dup2(fd, STDERR_FILENO);
2926
2927 if (fd >= 3)
2928 close_nointr_nofail(fd);
2929
2930 if (r < 0 || s < 0 || t < 0)
2931 return -errno;
2932
7862f62d
LP
2933 fd_cloexec(STDIN_FILENO, false);
2934 fd_cloexec(STDOUT_FILENO, false);
2935 fd_cloexec(STDERR_FILENO, false);
2936
843d2643
LP
2937 return 0;
2938}
2939
ade509ce
LP
2940int make_null_stdio(void) {
2941 int null_fd;
2942
cd3bd60a
LP
2943 null_fd = open("/dev/null", O_RDWR|O_NOCTTY);
2944 if (null_fd < 0)
ade509ce
LP
2945 return -errno;
2946
2947 return make_stdio(null_fd);
2948}
2949
8407a5d0
LP
2950bool is_device_path(const char *path) {
2951
2952 /* Returns true on paths that refer to a device, either in
2953 * sysfs or in /dev */
2954
2955 return
2956 path_startswith(path, "/dev/") ||
2957 path_startswith(path, "/sys/");
2958}
2959
01f78473
LP
2960int dir_is_empty(const char *path) {
2961 DIR *d;
2962 int r;
2963 struct dirent buf, *de;
2964
2965 if (!(d = opendir(path)))
2966 return -errno;
2967
2968 for (;;) {
2969 if ((r = readdir_r(d, &buf, &de)) > 0) {
2970 r = -r;
2971 break;
2972 }
2973
2974 if (!de) {
2975 r = 1;
2976 break;
2977 }
2978
2979 if (!ignore_file(de->d_name)) {
2980 r = 0;
2981 break;
2982 }
2983 }
2984
2985 closedir(d);
2986 return r;
2987}
2988
d3782d60
LP
2989unsigned long long random_ull(void) {
2990 int fd;
2991 uint64_t ull;
2992 ssize_t r;
2993
2994 if ((fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY)) < 0)
2995 goto fallback;
2996
eb22ac37 2997 r = loop_read(fd, &ull, sizeof(ull), true);
d3782d60
LP
2998 close_nointr_nofail(fd);
2999
3000 if (r != sizeof(ull))
3001 goto fallback;
3002
3003 return ull;
3004
3005fallback:
3006 return random() * RAND_MAX + random();
3007}
3008
5b6319dc
LP
3009void rename_process(const char name[8]) {
3010 assert(name);
3011
5d6b1584
LP
3012 /* This is a like a poor man's setproctitle(). It changes the
3013 * comm field, argv[0], and also the glibc's internally used
3014 * name of the process. For the first one a limit of 16 chars
3015 * applies, to the second one usually one of 10 (i.e. length
3016 * of "/sbin/init"), to the third one one of 7 (i.e. length of
3017 * "systemd"). If you pass a longer string it will be
3018 * truncated */
5b6319dc 3019
5d6b1584 3020 prctl(PR_SET_NAME, name);
5b6319dc
LP
3021
3022 if (program_invocation_name)
3023 strncpy(program_invocation_name, name, strlen(program_invocation_name));
9a0e6896
LP
3024
3025 if (saved_argc > 0) {
3026 int i;
3027
3028 if (saved_argv[0])
3029 strncpy(saved_argv[0], name, strlen(saved_argv[0]));
3030
3031 for (i = 1; i < saved_argc; i++) {
3032 if (!saved_argv[i])
3033 break;
3034
3035 memset(saved_argv[i], 0, strlen(saved_argv[i]));
3036 }
3037 }
5b6319dc
LP
3038}
3039
7d793605
LP
3040void sigset_add_many(sigset_t *ss, ...) {
3041 va_list ap;
3042 int sig;
3043
3044 assert(ss);
3045
3046 va_start(ap, ss);
3047 while ((sig = va_arg(ap, int)) > 0)
3048 assert_se(sigaddset(ss, sig) == 0);
3049 va_end(ap);
3050}
3051
ef2f1067
LP
3052char* gethostname_malloc(void) {
3053 struct utsname u;
3054
3055 assert_se(uname(&u) >= 0);
3056
344de609 3057 if (!isempty(u.nodename) && !streq(u.nodename, "(none)"))
ef2f1067
LP
3058 return strdup(u.nodename);
3059
3060 return strdup(u.sysname);
3061}
3062
344de609
LP
3063bool hostname_is_set(void) {
3064 struct utsname u;
3065
3066 assert_se(uname(&u) >= 0);
3067
3068 return !isempty(u.nodename) && !streq(u.nodename, "(none)");
3069}
3070
ef2f1067
LP
3071char* getlogname_malloc(void) {
3072 uid_t uid;
3073 long bufsize;
3074 char *buf, *name;
3075 struct passwd pwbuf, *pw = NULL;
3076 struct stat st;
3077
3078 if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0)
3079 uid = st.st_uid;
3080 else
3081 uid = getuid();
3082
3083 /* Shortcut things to avoid NSS lookups */
3084 if (uid == 0)
3085 return strdup("root");
3086
3087 if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) <= 0)
3088 bufsize = 4096;
3089
3090 if (!(buf = malloc(bufsize)))
3091 return NULL;
3092
3093 if (getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0 && pw) {
3094 name = strdup(pw->pw_name);
3095 free(buf);
3096 return name;
3097 }
3098
3099 free(buf);
3100
3101 if (asprintf(&name, "%lu", (unsigned long) uid) < 0)
3102 return NULL;
3103
3104 return name;
3105}
3106
fc116c6a
LP
3107int getttyname_malloc(int fd, char **r) {
3108 char path[PATH_MAX], *c;
618e02c7 3109 int k;
8c6db833
LP
3110
3111 assert(r);
ef2f1067 3112
fc116c6a 3113 if ((k = ttyname_r(fd, path, sizeof(path))) != 0)
618e02c7 3114 return -k;
ef2f1067
LP
3115
3116 char_array_0(path);
3117
fc116c6a 3118 if (!(c = strdup(startswith(path, "/dev/") ? path + 5 : path)))
8c6db833
LP
3119 return -ENOMEM;
3120
3121 *r = c;
3122 return 0;
3123}
3124
fc116c6a
LP
3125int getttyname_harder(int fd, char **r) {
3126 int k;
3127 char *s;
3128
3129 if ((k = getttyname_malloc(fd, &s)) < 0)
3130 return k;
3131
3132 if (streq(s, "tty")) {
3133 free(s);
4d6d6518 3134 return get_ctty(0, NULL, r);
fc116c6a
LP
3135 }
3136
3137 *r = s;
3138 return 0;
3139}
3140
4d6d6518 3141int get_ctty_devnr(pid_t pid, dev_t *d) {
fc116c6a 3142 int k;
4d6d6518 3143 char line[LINE_MAX], *p, *fn;
fc116c6a
LP
3144 unsigned long ttynr;
3145 FILE *f;
3146
4d6d6518
LP
3147 if (asprintf(&fn, "/proc/%lu/stat", (unsigned long) (pid <= 0 ? getpid() : pid)) < 0)
3148 return -ENOMEM;
3149
3150 f = fopen(fn, "re");
3151 free(fn);
3152 if (!f)
fc116c6a
LP
3153 return -errno;
3154
4d6d6518 3155 if (!fgets(line, sizeof(line), f)) {
35d50f55 3156 k = feof(f) ? -EIO : -errno;
fc116c6a
LP
3157 fclose(f);
3158 return k;
3159 }
3160
3161 fclose(f);
3162
4d6d6518
LP
3163 p = strrchr(line, ')');
3164 if (!p)
fc116c6a
LP
3165 return -EIO;
3166
3167 p++;
3168
3169 if (sscanf(p, " "
3170 "%*c " /* state */
3171 "%*d " /* ppid */
3172 "%*d " /* pgrp */
3173 "%*d " /* session */
3174 "%lu ", /* ttynr */
3175 &ttynr) != 1)
3176 return -EIO;
3177
3178 *d = (dev_t) ttynr;
3179 return 0;
3180}
3181
4d6d6518 3182int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
fc116c6a 3183 int k;
20c03b7b 3184 char fn[PATH_MAX], *s, *b, *p;
fc116c6a
LP
3185 dev_t devnr;
3186
3187 assert(r);
3188
4d6d6518
LP
3189 k = get_ctty_devnr(pid, &devnr);
3190 if (k < 0)
fc116c6a
LP
3191 return k;
3192
3193 snprintf(fn, sizeof(fn), "/dev/char/%u:%u", major(devnr), minor(devnr));
3194 char_array_0(fn);
3195
3196 if ((k = readlink_malloc(fn, &s)) < 0) {
3197
3198 if (k != -ENOENT)
3199 return k;
3200
46824d0e
LP
3201 /* This is an ugly hack */
3202 if (major(devnr) == 136) {
3203 if (asprintf(&b, "pts/%lu", (unsigned long) minor(devnr)) < 0)
3204 return -ENOMEM;
3205
3206 *r = b;
3207 if (_devnr)
3208 *_devnr = devnr;
3209
3210 return 0;
3211 }
3212
fc116c6a
LP
3213 /* Probably something like the ptys which have no
3214 * symlink in /dev/char. Let's return something
3215 * vaguely useful. */
3216
3217 if (!(b = strdup(fn + 5)))
3218 return -ENOMEM;
3219
3220 *r = b;
46824d0e
LP
3221 if (_devnr)
3222 *_devnr = devnr;
3223
fc116c6a
LP
3224 return 0;
3225 }
3226
3227 if (startswith(s, "/dev/"))
3228 p = s + 5;
3229 else if (startswith(s, "../"))
3230 p = s + 3;
3231 else
3232 p = s;
3233
3234 b = strdup(p);
3235 free(s);
3236
3237 if (!b)
3238 return -ENOMEM;
3239
3240 *r = b;
46824d0e
LP
3241 if (_devnr)
3242 *_devnr = devnr;
3243
fc116c6a
LP
3244 return 0;
3245}
3246
f56d5db9 3247int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
8c6db833
LP
3248 DIR *d;
3249 int ret = 0;
3250
3251 assert(fd >= 0);
3252
3253 /* This returns the first error we run into, but nevertheless
7925c22a 3254 * tries to go on. This closes the passed fd. */
8c6db833 3255
d4d046e3
LP
3256 d = fdopendir(fd);
3257 if (!d) {
8c6db833 3258 close_nointr_nofail(fd);
4c633005
LP
3259
3260 return errno == ENOENT ? 0 : -errno;
8c6db833
LP
3261 }
3262
3263 for (;;) {
3264 struct dirent buf, *de;
7925c22a
LP
3265 bool is_dir, keep_around;
3266 struct stat st;
8c6db833
LP
3267 int r;
3268
d4d046e3
LP
3269 r = readdir_r(d, &buf, &de);
3270 if (r != 0 && ret == 0) {
3271 ret = -r;
8c6db833
LP
3272 break;
3273 }
3274
3275 if (!de)
3276 break;
3277
3278 if (streq(de->d_name, ".") || streq(de->d_name, ".."))
3279 continue;
3280
7925c22a
LP
3281 if (de->d_type == DT_UNKNOWN ||
3282 honour_sticky ||
3283 (de->d_type == DT_DIR && root_dev)) {
8c6db833 3284 if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
4c633005 3285 if (ret == 0 && errno != ENOENT)
8c6db833
LP
3286 ret = -errno;
3287 continue;
3288 }
3289
3290 is_dir = S_ISDIR(st.st_mode);
7925c22a
LP
3291 keep_around =
3292 honour_sticky &&
3293 (st.st_uid == 0 || st.st_uid == getuid()) &&
3294 (st.st_mode & S_ISVTX);
ad293f5a 3295 } else {
8c6db833 3296 is_dir = de->d_type == DT_DIR;
7925c22a 3297 keep_around = false;
ad293f5a 3298 }
8c6db833
LP
3299
3300 if (is_dir) {
3301 int subdir_fd;
8c6db833 3302
597f43c7 3303 /* if root_dev is set, remove subdirectories only, if device is same as dir */
7925c22a
LP
3304 if (root_dev && st.st_dev != root_dev->st_dev)
3305 continue;
8c6db833 3306
7925c22a
LP
3307 subdir_fd = openat(fd, de->d_name,
3308 O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
3309 if (subdir_fd < 0) {
3310 if (ret == 0 && errno != ENOENT)
3311 ret = -errno;
3312 continue;
3313 }
3314
3315 r = rm_rf_children(subdir_fd, only_dirs, honour_sticky, root_dev);
3316 if (r < 0 && ret == 0)
3317 ret = r;
3318
3319 if (!keep_around)
3320 if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
ad293f5a
LP
3321 if (ret == 0 && errno != ENOENT)
3322 ret = -errno;
3323 }
3324
3325 } else if (!only_dirs && !keep_around) {
8c6db833
LP
3326
3327 if (unlinkat(fd, de->d_name, 0) < 0) {
4c633005 3328 if (ret == 0 && errno != ENOENT)
8c6db833
LP
3329 ret = -errno;
3330 }
3331 }
3332 }
3333
3334 closedir(d);
3335
3336 return ret;
3337}
3338
f56d5db9
LP
3339int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
3340 struct statfs s;
3341
3342 assert(fd >= 0);
3343
3344 if (fstatfs(fd, &s) < 0) {
3345 close_nointr_nofail(fd);
3346 return -errno;
3347 }
3348
3349 /* We refuse to clean disk file systems with this call. This
3350 * is extra paranoia just to be sure we never ever remove
3351 * non-state data */
3352
3353 if (s.f_type != TMPFS_MAGIC &&
3354 s.f_type != RAMFS_MAGIC) {
3355 log_error("Attempted to remove disk file system, and we can't allow that.");
3356 close_nointr_nofail(fd);
3357 return -EPERM;
3358 }
3359
3360 return rm_rf_children_dangerous(fd, only_dirs, honour_sticky, root_dev);
3361}
3362
3363static int rm_rf_internal(const char *path, bool only_dirs, bool delete_root, bool honour_sticky, bool dangerous) {
3364 int fd, r;
3365 struct statfs s;
8c6db833
LP
3366
3367 assert(path);
3368
f56d5db9
LP
3369 /* We refuse to clean the root file system with this
3370 * call. This is extra paranoia to never cause a really
3371 * seriously broken system. */
3372 if (path_equal(path, "/")) {
3373 log_error("Attempted to remove entire root file system, and we can't allow that.");
3374 return -EPERM;
3375 }
461b1822 3376
d4d046e3
LP
3377 fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
3378 if (fd < 0) {
8c6db833
LP
3379
3380 if (errno != ENOTDIR)
3381 return -errno;
3382
f56d5db9
LP
3383 if (!dangerous) {
3384 if (statfs(path, &s) < 0)
3385 return -errno;
3386
3387 if (s.f_type != TMPFS_MAGIC &&
3388 s.f_type != RAMFS_MAGIC) {
3389 log_error("Attempted to remove disk file system, and we can't allow that.");
3390 return -EPERM;
3391 }
3392 }
3393
8c6db833 3394 if (delete_root && !only_dirs)
d4d046e3 3395 if (unlink(path) < 0 && errno != ENOENT)
8c6db833
LP
3396 return -errno;
3397
3398 return 0;
3399 }
3400
f56d5db9
LP
3401 if (!dangerous) {
3402 if (fstatfs(fd, &s) < 0) {
3403 close_nointr_nofail(fd);
3404 return -errno;
3405 }
ad293f5a 3406
f56d5db9
LP
3407 if (s.f_type != TMPFS_MAGIC &&
3408 s.f_type != RAMFS_MAGIC) {
3409 log_error("Attempted to remove disk file system, and we can't allow that.");
3410 close_nointr_nofail(fd);
3411 return -EPERM;
3412 }
3413 }
3414
3415 r = rm_rf_children_dangerous(fd, only_dirs, honour_sticky, NULL);
ad293f5a
LP
3416 if (delete_root) {
3417
8d53b453 3418 if (honour_sticky && file_is_priv_sticky(path) > 0)
ad293f5a 3419 return r;
8c6db833 3420
e27796a0 3421 if (rmdir(path) < 0 && errno != ENOENT) {
8c6db833
LP
3422 if (r == 0)
3423 r = -errno;
3424 }
ad293f5a 3425 }
8c6db833
LP
3426
3427 return r;
3428}
3429
f56d5db9
LP
3430int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) {
3431 return rm_rf_internal(path, only_dirs, delete_root, honour_sticky, false);
3432}
3433
3434int rm_rf_dangerous(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) {
3435 return rm_rf_internal(path, only_dirs, delete_root, honour_sticky, true);
3436}
3437
8c6db833
LP
3438int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
3439 assert(path);
3440
3441 /* Under the assumption that we are running privileged we
3442 * first change the access mode and only then hand out
3443 * ownership to avoid a window where access is too open. */
3444
8d53b453
LP
3445 if (mode != (mode_t) -1)
3446 if (chmod(path, mode) < 0)
3447 return -errno;
8c6db833 3448
8d53b453
LP
3449 if (uid != (uid_t) -1 || gid != (gid_t) -1)
3450 if (chown(path, uid, gid) < 0)
3451 return -errno;
8c6db833
LP
3452
3453 return 0;
ef2f1067
LP
3454}
3455
f4b47811
LP
3456int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) {
3457 assert(fd >= 0);
3458
3459 /* Under the assumption that we are running privileged we
3460 * first change the access mode and only then hand out
3461 * ownership to avoid a window where access is too open. */
3462
3463 if (fchmod(fd, mode) < 0)
3464 return -errno;
3465
3466 if (fchown(fd, uid, gid) < 0)
3467 return -errno;
3468
3469 return 0;
3470}
3471
82c121a4
LP
3472cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
3473 cpu_set_t *r;
3474 unsigned n = 1024;
3475
3476 /* Allocates the cpuset in the right size */
3477
3478 for (;;) {
3479 if (!(r = CPU_ALLOC(n)))
3480 return NULL;
3481
3482 if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), r) >= 0) {
3483 CPU_ZERO_S(CPU_ALLOC_SIZE(n), r);
3484
3485 if (ncpus)
3486 *ncpus = n;
3487
3488 return r;
3489 }
3490
3491 CPU_FREE(r);
3492
3493 if (errno != EINVAL)
3494 return NULL;
3495
3496 n *= 2;
3497 }
3498}
3499
67e5cc4f 3500void status_vprintf(const char *status, bool ellipse, const char *format, va_list ap) {
9ab7a8d2
MS
3501 char *s = NULL;
3502 static const char status_indent[] = " "; /* "[" STATUS "] " */
3503 int fd = -1;
81beb750
LP
3504 struct iovec iovec[5];
3505 int n = 0;
9e58ff9c
LP
3506
3507 assert(format);
3508
9ab7a8d2 3509 /* This is independent of logging, as status messages are
9e58ff9c
LP
3510 * optional and go exclusively to the console. */
3511
3512 if (vasprintf(&s, format, ap) < 0)
3513 goto finish;
3514
67e5cc4f 3515 fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
81beb750 3516 if (fd < 0)
9e58ff9c
LP
3517 goto finish;
3518
67e5cc4f 3519 if (ellipse) {
9ab7a8d2
MS
3520 char *e;
3521 size_t emax, sl;
3522 int c;
3523
67e5cc4f
LP
3524 c = fd_columns(fd);
3525 if (c <= 0)
3526 c = 80;
81beb750 3527
9ab7a8d2
MS
3528 sl = status ? strlen(status_indent) : 0;
3529
3530 emax = c - sl - 1;
3531 if (emax < 3)
3532 emax = 3;
81beb750 3533
67e5cc4f
LP
3534 e = ellipsize(s, emax, 75);
3535 if (e) {
3536 free(s);
3537 s = e;
3538 }
81beb750
LP
3539 }
3540
3541 zero(iovec);
81beb750 3542
9ab7a8d2
MS
3543 if (status) {
3544 if (!isempty(status)) {
3545 IOVEC_SET_STRING(iovec[n++], "[");
3546 IOVEC_SET_STRING(iovec[n++], status);
3547 IOVEC_SET_STRING(iovec[n++], "] ");
3548 } else
3549 IOVEC_SET_STRING(iovec[n++], status_indent);
81beb750
LP
3550 }
3551
9ab7a8d2
MS
3552 IOVEC_SET_STRING(iovec[n++], s);
3553 IOVEC_SET_STRING(iovec[n++], "\n");
81beb750
LP
3554
3555 writev(fd, iovec, n);
9e58ff9c
LP
3556
3557finish:
3558 free(s);
3559
3560 if (fd >= 0)
3561 close_nointr_nofail(fd);
3562}
3563
67e5cc4f 3564void status_printf(const char *status, bool ellipse, const char *format, ...) {
c846ff47
LP
3565 va_list ap;
3566
3567 assert(format);
3568
3569 va_start(ap, format);
67e5cc4f 3570 status_vprintf(status, ellipse, format, ap);
c846ff47
LP
3571 va_end(ap);
3572}
3573
3574void status_welcome(void) {
10aa7034
LP
3575 char *pretty_name = NULL, *ansi_color = NULL;
3576 const char *const_pretty = NULL, *const_color = NULL;
3577 int r;
c846ff47 3578
10aa7034
LP
3579 if ((r = parse_env_file("/etc/os-release", NEWLINE,
3580 "PRETTY_NAME", &pretty_name,
3581 "ANSI_COLOR", &ansi_color,
3582 NULL)) < 0) {
c846ff47 3583
10aa7034
LP
3584 if (r != -ENOENT)
3585 log_warning("Failed to read /etc/os-release: %s", strerror(-r));
3586 }
c846ff47 3587
10aa7034
LP
3588 if (!pretty_name && !const_pretty)
3589 const_pretty = "Linux";
3590
3591 if (!ansi_color && !const_color)
3592 const_color = "1";
3593
81beb750 3594 status_printf(NULL,
67e5cc4f 3595 false,
81beb750 3596 "\nWelcome to \x1B[%sm%s\x1B[0m!\n",
10aa7034
LP
3597 const_color ? const_color : ansi_color,
3598 const_pretty ? const_pretty : pretty_name);
86a3475b
LP
3599
3600 free(ansi_color);
3601 free(pretty_name);
c846ff47
LP
3602}
3603
fab56fc5
LP
3604char *replace_env(const char *format, char **env) {
3605 enum {
3606 WORD,
c24eb49e 3607 CURLY,
fab56fc5
LP
3608 VARIABLE
3609 } state = WORD;
3610
3611 const char *e, *word = format;
3612 char *r = NULL, *k;
3613
3614 assert(format);
3615
3616 for (e = format; *e; e ++) {
3617
3618 switch (state) {
3619
3620 case WORD:
3621 if (*e == '$')
c24eb49e 3622 state = CURLY;
fab56fc5
LP
3623 break;
3624
c24eb49e
LP
3625 case CURLY:
3626 if (*e == '{') {
fab56fc5
LP
3627 if (!(k = strnappend(r, word, e-word-1)))
3628 goto fail;
3629
3630 free(r);
3631 r = k;
3632
3633 word = e-1;
3634 state = VARIABLE;
3635
3636 } else if (*e == '$') {
3637 if (!(k = strnappend(r, word, e-word)))
3638 goto fail;
3639
3640 free(r);
3641 r = k;
3642
3643 word = e+1;
3644 state = WORD;
3645 } else
3646 state = WORD;
3647 break;
3648
3649 case VARIABLE:
c24eb49e 3650 if (*e == '}') {
b95cf362 3651 const char *t;
fab56fc5 3652
b95cf362
LP
3653 if (!(t = strv_env_get_with_length(env, word+2, e-word-2)))
3654 t = "";
fab56fc5 3655
b95cf362
LP
3656 if (!(k = strappend(r, t)))
3657 goto fail;
fab56fc5 3658
b95cf362
LP
3659 free(r);
3660 r = k;
fab56fc5 3661
b95cf362 3662 word = e+1;
fab56fc5
LP
3663 state = WORD;
3664 }
3665 break;
3666 }
3667 }
3668
3669 if (!(k = strnappend(r, word, e-word)))
3670 goto fail;
3671
3672 free(r);
3673 return k;
3674
3675fail:
3676 free(r);
3677 return NULL;
3678}
3679
3680char **replace_env_argv(char **argv, char **env) {
3681 char **r, **i;
c24eb49e
LP
3682 unsigned k = 0, l = 0;
3683
3684 l = strv_length(argv);
fab56fc5 3685
c24eb49e 3686 if (!(r = new(char*, l+1)))
fab56fc5
LP
3687 return NULL;
3688
3689 STRV_FOREACH(i, argv) {
c24eb49e
LP
3690
3691 /* If $FOO appears as single word, replace it by the split up variable */
b95cf362
LP
3692 if ((*i)[0] == '$' && (*i)[1] != '{') {
3693 char *e;
3694 char **w, **m;
3695 unsigned q;
c24eb49e 3696
b95cf362 3697 if ((e = strv_env_get(env, *i+1))) {
c24eb49e
LP
3698
3699 if (!(m = strv_split_quoted(e))) {
3700 r[k] = NULL;
3701 strv_free(r);
3702 return NULL;
3703 }
b95cf362
LP
3704 } else
3705 m = NULL;
c24eb49e 3706
b95cf362
LP
3707 q = strv_length(m);
3708 l = l + q - 1;
c24eb49e 3709
b95cf362
LP
3710 if (!(w = realloc(r, sizeof(char*) * (l+1)))) {
3711 r[k] = NULL;
3712 strv_free(r);
3713 strv_free(m);
3714 return NULL;
3715 }
c24eb49e 3716
b95cf362
LP
3717 r = w;
3718 if (m) {
c24eb49e
LP
3719 memcpy(r + k, m, q * sizeof(char*));
3720 free(m);
c24eb49e 3721 }
b95cf362
LP
3722
3723 k += q;
3724 continue;
c24eb49e
LP
3725 }
3726
3727 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
fab56fc5
LP
3728 if (!(r[k++] = replace_env(*i, env))) {
3729 strv_free(r);
3730 return NULL;
3731 }
3732 }
3733
3734 r[k] = NULL;
3735 return r;
3736}
3737
81beb750
LP
3738int fd_columns(int fd) {
3739 struct winsize ws;
3740 zero(ws);
3741
3742 if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
3743 return -errno;
3744
3745 if (ws.ws_col <= 0)
3746 return -EIO;
3747
3748 return ws.ws_col;
3749}
3750
72f59706 3751unsigned columns(void) {
fa776d8e
LP
3752 static __thread int parsed_columns = 0;
3753 const char *e;
3754
3bfc7184 3755 if (_likely_(parsed_columns > 0))
fa776d8e
LP
3756 return parsed_columns;
3757
81beb750
LP
3758 e = getenv("COLUMNS");
3759 if (e)
fa776d8e
LP
3760 parsed_columns = atoi(e);
3761
81beb750
LP
3762 if (parsed_columns <= 0)
3763 parsed_columns = fd_columns(STDOUT_FILENO);
fa776d8e
LP
3764
3765 if (parsed_columns <= 0)
3766 parsed_columns = 80;
3767
3768 return parsed_columns;
3769}
3770
8f2d43a0
LP
3771int fd_lines(int fd) {
3772 struct winsize ws;
3773 zero(ws);
3774
3775 if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
3776 return -errno;
3777
3778 if (ws.ws_row <= 0)
3779 return -EIO;
3780
3781 return ws.ws_row;
3782}
3783
3784unsigned lines(void) {
3785 static __thread int parsed_lines = 0;
3786 const char *e;
3787
3788 if (_likely_(parsed_lines > 0))
3789 return parsed_lines;
3790
3791 e = getenv("LINES");
3792 if (e)
3793 parsed_lines = atoi(e);
3794
3795 if (parsed_lines <= 0)
3796 parsed_lines = fd_lines(STDOUT_FILENO);
3797
3798 if (parsed_lines <= 0)
3799 parsed_lines = 25;
3800
3801 return parsed_lines;
3802}
3803
b4f10a5e
LP
3804int running_in_chroot(void) {
3805 struct stat a, b;
3806
3807 zero(a);
3808 zero(b);
3809
3810 /* Only works as root */
3811
3812 if (stat("/proc/1/root", &a) < 0)
3813 return -errno;
3814
3815 if (stat("/", &b) < 0)
3816 return -errno;
3817
3818 return
3819 a.st_dev != b.st_dev ||
3820 a.st_ino != b.st_ino;
3821}
3822
72f59706
LP
3823char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
3824 size_t x;
8fe914ec
LP
3825 char *r;
3826
3827 assert(s);
3828 assert(percent <= 100);
72f59706 3829 assert(new_length >= 3);
8fe914ec 3830
72f59706
LP
3831 if (old_length <= 3 || old_length <= new_length)
3832 return strndup(s, old_length);
8fe914ec 3833
72f59706
LP
3834 r = new0(char, new_length+1);
3835 if (!r)
8fe914ec
LP
3836 return r;
3837
72f59706 3838 x = (new_length * percent) / 100;
8fe914ec 3839
72f59706
LP
3840 if (x > new_length - 3)
3841 x = new_length - 3;
8fe914ec
LP
3842
3843 memcpy(r, s, x);
3844 r[x] = '.';
3845 r[x+1] = '.';
3846 r[x+2] = '.';
3847 memcpy(r + x + 3,
72f59706
LP
3848 s + old_length - (new_length - x - 3),
3849 new_length - x - 3);
8fe914ec
LP
3850
3851 return r;
3852}
3853
72f59706
LP
3854char *ellipsize(const char *s, size_t length, unsigned percent) {
3855 return ellipsize_mem(s, strlen(s), length, percent);
3856}
3857
f6144808
LP
3858int touch(const char *path) {
3859 int fd;
3860
3861 assert(path);
3862
14f3c825 3863 if ((fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0644)) < 0)
f6144808
LP
3864 return -errno;
3865
3866 close_nointr_nofail(fd);
3867 return 0;
3868}
afea26ad 3869
97c4a07d 3870char *unquote(const char *s, const char* quotes) {
11ce3427
LP
3871 size_t l;
3872 assert(s);
3873
31ed59c5
LP
3874 l = strlen(s);
3875 if (l < 2)
11ce3427
LP
3876 return strdup(s);
3877
97c4a07d 3878 if (strchr(quotes, s[0]) && s[l-1] == s[0])
11ce3427
LP
3879 return strndup(s+1, l-2);
3880
3881 return strdup(s);
3882}
3883
5f7c426e
LP
3884char *normalize_env_assignment(const char *s) {
3885 char *name, *value, *p, *r;
3886
3887 p = strchr(s, '=');
3888
3889 if (!p) {
3890 if (!(r = strdup(s)))
3891 return NULL;
3892
3893 return strstrip(r);
3894 }
3895
3896 if (!(name = strndup(s, p - s)))
3897 return NULL;
3898
3899 if (!(p = strdup(p+1))) {
3900 free(name);
3901 return NULL;
3902 }
3903
3904 value = unquote(strstrip(p), QUOTES);
3905 free(p);
3906
3907 if (!value) {
5f7c426e
LP
3908 free(name);
3909 return NULL;
3910 }
3911
3912 if (asprintf(&r, "%s=%s", name, value) < 0)
3913 r = NULL;
3914
3915 free(value);
3916 free(name);
3917
3918 return r;
3919}
3920
8e12a6ae 3921int wait_for_terminate(pid_t pid, siginfo_t *status) {
1968a360
LP
3922 siginfo_t dummy;
3923
2e78aa99 3924 assert(pid >= 1);
1968a360
LP
3925
3926 if (!status)
3927 status = &dummy;
2e78aa99
LP
3928
3929 for (;;) {
8e12a6ae
LP
3930 zero(*status);
3931
3932 if (waitid(P_PID, pid, status, WEXITED) < 0) {
2e78aa99
LP
3933
3934 if (errno == EINTR)
3935 continue;
3936
3937 return -errno;
3938 }
3939
3940 return 0;
3941 }
3942}
3943
97c4a07d
LP
3944int wait_for_terminate_and_warn(const char *name, pid_t pid) {
3945 int r;
3946 siginfo_t status;
3947
3948 assert(name);
3949 assert(pid > 1);
3950
3951 if ((r = wait_for_terminate(pid, &status)) < 0) {
3952 log_warning("Failed to wait for %s: %s", name, strerror(-r));
3953 return r;
3954 }
3955
3956 if (status.si_code == CLD_EXITED) {
3957 if (status.si_status != 0) {
3958 log_warning("%s failed with error code %i.", name, status.si_status);
0a27cf3f 3959 return status.si_status;
97c4a07d
LP
3960 }
3961
3962 log_debug("%s succeeded.", name);
3963 return 0;
3964
3965 } else if (status.si_code == CLD_KILLED ||
3966 status.si_code == CLD_DUMPED) {
3967
3968 log_warning("%s terminated by signal %s.", name, signal_to_string(status.si_status));
3969 return -EPROTO;
3970 }
3971
3972 log_warning("%s failed due to unknown reason.", name);
3973 return -EPROTO;
3974
3975}
3976
6a39419f 3977_noreturn_ void freeze(void) {
720ce21d
LP
3978
3979 /* Make sure nobody waits for us on a socket anymore */
3980 close_all_fds(NULL, 0);
3981
c29597a1
LP
3982 sync();
3983
3c14d26c
LP
3984 for (;;)
3985 pause();
3986}
3987
00dc5d76
LP
3988bool null_or_empty(struct stat *st) {
3989 assert(st);
3990
3991 if (S_ISREG(st->st_mode) && st->st_size <= 0)
3992 return true;
3993
c8f26f42 3994 if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
00dc5d76
LP
3995 return true;
3996
3997 return false;
3998}
3999
83096483
LP
4000int null_or_empty_path(const char *fn) {
4001 struct stat st;
4002
4003 assert(fn);
4004
4005 if (stat(fn, &st) < 0)
4006 return -errno;
4007
4008 return null_or_empty(&st);
4009}
4010
a247755d 4011DIR *xopendirat(int fd, const char *name, int flags) {
c4731d11
LP
4012 int nfd;
4013 DIR *d;
4014
4015 if ((nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags)) < 0)
4016 return NULL;
4017
4018 if (!(d = fdopendir(nfd))) {
4019 close_nointr_nofail(nfd);
4020 return NULL;
4021 }
4022
4023 return d;
3b63d2d3
LP
4024}
4025
8a0867d6
LP
4026int signal_from_string_try_harder(const char *s) {
4027 int signo;
4028 assert(s);
4029
4030 if ((signo = signal_from_string(s)) <= 0)
4031 if (startswith(s, "SIG"))
4032 return signal_from_string(s+3);
4033
4034 return signo;
4035}
4036
10717a1a
LP
4037void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
4038
4039 assert(f);
4040 assert(name);
4041 assert(t);
4042
4043 if (!dual_timestamp_is_set(t))
4044 return;
4045
4046 fprintf(f, "%s=%llu %llu\n",
4047 name,
4048 (unsigned long long) t->realtime,
4049 (unsigned long long) t->monotonic);
4050}
4051
799fd0fd 4052void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
10717a1a
LP
4053 unsigned long long a, b;
4054
10717a1a
LP
4055 assert(value);
4056 assert(t);
4057
4058 if (sscanf(value, "%lli %llu", &a, &b) != 2)
4059 log_debug("Failed to parse finish timestamp value %s", value);
4060 else {
4061 t->realtime = a;
4062 t->monotonic = b;
4063 }
4064}
4065
e23a0ce8
LP
4066char *fstab_node_to_udev_node(const char *p) {
4067 char *dn, *t, *u;
4068 int r;
4069
4070 /* FIXME: to follow udev's logic 100% we need to leave valid
4071 * UTF8 chars unescaped */
4072
4073 if (startswith(p, "LABEL=")) {
4074
4075 if (!(u = unquote(p+6, "\"\'")))
4076 return NULL;
4077
4078 t = xescape(u, "/ ");
4079 free(u);
4080
4081 if (!t)
4082 return NULL;
4083
4084 r = asprintf(&dn, "/dev/disk/by-label/%s", t);
4085 free(t);
4086
4087 if (r < 0)
4088 return NULL;
4089
4090 return dn;
4091 }
4092
4093 if (startswith(p, "UUID=")) {
4094
4095 if (!(u = unquote(p+5, "\"\'")))
4096 return NULL;
4097
4098 t = xescape(u, "/ ");
4099 free(u);
4100
4101 if (!t)
4102 return NULL;
4103
0058d7b9 4104 r = asprintf(&dn, "/dev/disk/by-uuid/%s", t);
e23a0ce8
LP
4105 free(t);
4106
4107 if (r < 0)
4108 return NULL;
4109
4110 return dn;
4111 }
4112
4113 return strdup(p);
4114}
4115
f212ac12
LP
4116bool tty_is_vc(const char *tty) {
4117 assert(tty);
4118
4119 if (startswith(tty, "/dev/"))
4120 tty += 5;
4121
98a28fef
LP
4122 return vtnr_from_tty(tty) >= 0;
4123}
4124
d1122ad5
LP
4125bool tty_is_console(const char *tty) {
4126 assert(tty);
4127
4128 if (startswith(tty, "/dev/"))
4129 tty += 5;
4130
4131 return streq(tty, "console");
4132}
4133
98a28fef
LP
4134int vtnr_from_tty(const char *tty) {
4135 int i, r;
4136
4137 assert(tty);
4138
4139 if (startswith(tty, "/dev/"))
4140 tty += 5;
4141
4142 if (!startswith(tty, "tty") )
4143 return -EINVAL;
4144
4145 if (tty[3] < '0' || tty[3] > '9')
4146 return -EINVAL;
4147
4148 r = safe_atoi(tty+3, &i);
4149 if (r < 0)
4150 return r;
4151
4152 if (i < 0 || i > 63)
4153 return -EINVAL;
4154
4155 return i;
f212ac12
LP
4156}
4157
3043935f 4158bool tty_is_vc_resolve(const char *tty) {
3030ccd7 4159 char *active = NULL;
3043935f 4160 bool b;
3030ccd7 4161
e3aa71c3
LP
4162 assert(tty);
4163
4164 if (startswith(tty, "/dev/"))
4165 tty += 5;
4166
3d9a4122
LP
4167 /* Resolve where /dev/console is pointing to, if /sys is
4168 * actually ours (i.e. not read-only-mounted which is a sign
4169 * for container setups) */
4170 if (streq(tty, "console") && path_is_read_only_fs("/sys") <= 0)
3030ccd7 4171 if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) {
079a09fb
LP
4172 /* If multiple log outputs are configured the
4173 * last one is what /dev/console points to */
3043935f
LP
4174 tty = strrchr(active, ' ');
4175 if (tty)
079a09fb
LP
4176 tty++;
4177 else
4178 tty = active;
3030ccd7
LP
4179 }
4180
3043935f 4181 b = tty_is_vc(tty);
3030ccd7 4182 free(active);
e3aa71c3 4183
3043935f
LP
4184 return b;
4185}
4186
4187const char *default_term_for_tty(const char *tty) {
4188 assert(tty);
4189
acda6a05 4190 return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt102";
e3aa71c3
LP
4191}
4192
87d2c1ff 4193bool dirent_is_file(const struct dirent *de) {
fb19a739
LP
4194 assert(de);
4195
4196 if (ignore_file(de->d_name))
4197 return false;
4198
4199 if (de->d_type != DT_REG &&
4200 de->d_type != DT_LNK &&
4201 de->d_type != DT_UNKNOWN)
4202 return false;
4203
4204 return true;
4205}
4206
87d2c1ff
LP
4207bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) {
4208 assert(de);
4209
4210 if (!dirent_is_file(de))
4211 return false;
4212
4213 return endswith(de->d_name, suffix);
4214}
4215
83cc030f
LP
4216void execute_directory(const char *directory, DIR *d, char *argv[]) {
4217 DIR *_d = NULL;
4218 struct dirent *de;
4219 Hashmap *pids = NULL;
4220
4221 assert(directory);
4222
4223 /* Executes all binaries in a directory in parallel and waits
4224 * until all they all finished. */
4225
4226 if (!d) {
4227 if (!(_d = opendir(directory))) {
4228
4229 if (errno == ENOENT)
4230 return;
4231
4232 log_error("Failed to enumerate directory %s: %m", directory);
4233 return;
4234 }
4235
4236 d = _d;
4237 }
4238
4239 if (!(pids = hashmap_new(trivial_hash_func, trivial_compare_func))) {
4240 log_error("Failed to allocate set.");
4241 goto finish;
4242 }
4243
4244 while ((de = readdir(d))) {
4245 char *path;
4246 pid_t pid;
4247 int k;
4248
fb19a739 4249 if (!dirent_is_file(de))
83cc030f
LP
4250 continue;
4251
4252 if (asprintf(&path, "%s/%s", directory, de->d_name) < 0) {
4253 log_error("Out of memory");
4254 continue;
4255 }
4256
4257 if ((pid = fork()) < 0) {
4258 log_error("Failed to fork: %m");
4259 free(path);
4260 continue;
4261 }
4262
4263 if (pid == 0) {
4264 char *_argv[2];
4265 /* Child */
4266
4267 if (!argv) {
4268 _argv[0] = path;
4269 _argv[1] = NULL;
4270 argv = _argv;
4271 } else
6edd7d0a 4272 argv[0] = path;
83cc030f
LP
4273
4274 execv(path, argv);
4275
4276 log_error("Failed to execute %s: %m", path);
4277 _exit(EXIT_FAILURE);
4278 }
4279
4280 log_debug("Spawned %s as %lu", path, (unsigned long) pid);
4281
4282 if ((k = hashmap_put(pids, UINT_TO_PTR(pid), path)) < 0) {
4283 log_error("Failed to add PID to set: %s", strerror(-k));
4284 free(path);
4285 }
4286 }
4287
4288 while (!hashmap_isempty(pids)) {
ec3f9b53 4289 pid_t pid = PTR_TO_UINT(hashmap_first_key(pids));
83cc030f
LP
4290 siginfo_t si;
4291 char *path;
4292
4293 zero(si);
ec3f9b53 4294 if (waitid(P_PID, pid, &si, WEXITED) < 0) {
83cc030f
LP
4295
4296 if (errno == EINTR)
4297 continue;
4298
4299 log_error("waitid() failed: %m");
4300 goto finish;
4301 }
4302
4303 if ((path = hashmap_remove(pids, UINT_TO_PTR(si.si_pid)))) {
4304 if (!is_clean_exit(si.si_code, si.si_status)) {
4305 if (si.si_code == CLD_EXITED)
4306 log_error("%s exited with exit status %i.", path, si.si_status);
4307 else
4308 log_error("%s terminated by signal %s.", path, signal_to_string(si.si_status));
4309 } else
4310 log_debug("%s exited successfully.", path);
4311
4312 free(path);
4313 }
4314 }
4315
4316finish:
4317 if (_d)
4318 closedir(_d);
4319
4320 if (pids)
4321 hashmap_free_free(pids);
4322}
4323
430c18ed
LP
4324int kill_and_sigcont(pid_t pid, int sig) {
4325 int r;
4326
4327 r = kill(pid, sig) < 0 ? -errno : 0;
4328
4329 if (r >= 0)
4330 kill(pid, SIGCONT);
4331
4332 return r;
4333}
4334
05feefe0
LP
4335bool nulstr_contains(const char*nulstr, const char *needle) {
4336 const char *i;
4337
4338 if (!nulstr)
4339 return false;
4340
4341 NULSTR_FOREACH(i, nulstr)
4342 if (streq(i, needle))
4343 return true;
4344
4345 return false;
4346}
4347
6faa1114 4348bool plymouth_running(void) {
9408a2d2 4349 return access("/run/plymouth/pid", F_OK) >= 0;
6faa1114
LP
4350}
4351
7c3b203c
LP
4352void parse_syslog_priority(char **p, int *priority) {
4353 int a = 0, b = 0, c = 0;
4354 int k;
4355
4356 assert(p);
4357 assert(*p);
4358 assert(priority);
4359
4360 if ((*p)[0] != '<')
4361 return;
4362
4363 if (!strchr(*p, '>'))
4364 return;
4365
4366 if ((*p)[2] == '>') {
4367 c = undecchar((*p)[1]);
4368 k = 3;
4369 } else if ((*p)[3] == '>') {
4370 b = undecchar((*p)[1]);
4371 c = undecchar((*p)[2]);
4372 k = 4;
4373 } else if ((*p)[4] == '>') {
4374 a = undecchar((*p)[1]);
4375 b = undecchar((*p)[2]);
4376 c = undecchar((*p)[3]);
4377 k = 5;
4378 } else
4379 return;
4380
4381 if (a < 0 || b < 0 || c < 0)
4382 return;
4383
4384 *priority = a*100+b*10+c;
4385 *p += k;
4386}
4387
87d2c1ff
LP
4388void skip_syslog_pid(char **buf) {
4389 char *p;
4390
4391 assert(buf);
4392 assert(*buf);
4393
4394 p = *buf;
4395
4396 if (*p != '[')
4397 return;
4398
4399 p++;
4400 p += strspn(p, "0123456789");
4401
4402 if (*p != ']')
4403 return;
4404
4405 p++;
4406
4407 *buf = p;
4408}
4409
4410void skip_syslog_date(char **buf) {
4411 enum {
4412 LETTER,
4413 SPACE,
4414 NUMBER,
4415 SPACE_OR_NUMBER,
4416 COLON
4417 } sequence[] = {
4418 LETTER, LETTER, LETTER,
4419 SPACE,
4420 SPACE_OR_NUMBER, NUMBER,
4421 SPACE,
4422 SPACE_OR_NUMBER, NUMBER,
4423 COLON,
4424 SPACE_OR_NUMBER, NUMBER,
4425 COLON,
4426 SPACE_OR_NUMBER, NUMBER,
4427 SPACE
4428 };
4429
4430 char *p;
4431 unsigned i;
4432
4433 assert(buf);
4434 assert(*buf);
4435
4436 p = *buf;
4437
4438 for (i = 0; i < ELEMENTSOF(sequence); i++, p++) {
4439
4440 if (!*p)
4441 return;
4442
4443 switch (sequence[i]) {
4444
4445 case SPACE:
4446 if (*p != ' ')
4447 return;
4448 break;
4449
4450 case SPACE_OR_NUMBER:
4451 if (*p == ' ')
4452 break;
4453
4454 /* fall through */
4455
4456 case NUMBER:
4457 if (*p < '0' || *p > '9')
4458 return;
4459
4460 break;
4461
4462 case LETTER:
4463 if (!(*p >= 'A' && *p <= 'Z') &&
4464 !(*p >= 'a' && *p <= 'z'))
4465 return;
4466
4467 break;
4468
4469 case COLON:
4470 if (*p != ':')
4471 return;
4472 break;
4473
4474 }
4475 }
4476
4477 *buf = p;
4478}
4479
9beb3f4d
LP
4480char* strshorten(char *s, size_t l) {
4481 assert(s);
4482
4483 if (l < strlen(s))
4484 s[l] = 0;
4485
4486 return s;
4487}
4488
4489static bool hostname_valid_char(char c) {
4490 return
4491 (c >= 'a' && c <= 'z') ||
4492 (c >= 'A' && c <= 'Z') ||
4493 (c >= '0' && c <= '9') ||
4494 c == '-' ||
4495 c == '_' ||
4496 c == '.';
4497}
4498
4499bool hostname_is_valid(const char *s) {
4500 const char *p;
4501
4502 if (isempty(s))
4503 return false;
4504
4505 for (p = s; *p; p++)
4506 if (!hostname_valid_char(*p))
4507 return false;
4508
4509 if (p-s > HOST_NAME_MAX)
4510 return false;
4511
4512 return true;
4513}
4514
4515char* hostname_cleanup(char *s) {
4516 char *p, *d;
4517
4518 for (p = s, d = s; *p; p++)
4519 if ((*p >= 'a' && *p <= 'z') ||
4520 (*p >= 'A' && *p <= 'Z') ||
4521 (*p >= '0' && *p <= '9') ||
4522 *p == '-' ||
4523 *p == '_' ||
4524 *p == '.')
4525 *(d++) = *p;
4526
4527 *d = 0;
4528
4529 strshorten(s, HOST_NAME_MAX);
4530 return s;
4531}
4532
1325aa42
LP
4533int pipe_eof(int fd) {
4534 struct pollfd pollfd;
4535 int r;
4536
4537 zero(pollfd);
4538 pollfd.fd = fd;
4539 pollfd.events = POLLIN|POLLHUP;
4540
4541 r = poll(&pollfd, 1, 0);
4542 if (r < 0)
4543 return -errno;
4544
4545 if (r == 0)
4546 return 0;
4547
4548 return pollfd.revents & POLLHUP;
4549}
4550
8f2d43a0 4551int fd_wait_for_event(int fd, int event, usec_t t) {
df50185b
LP
4552 struct pollfd pollfd;
4553 int r;
4554
4555 zero(pollfd);
4556 pollfd.fd = fd;
4557 pollfd.events = event;
4558
8f2d43a0 4559 r = poll(&pollfd, 1, t == (usec_t) -1 ? -1 : (int) (t / USEC_PER_MSEC));
df50185b
LP
4560 if (r < 0)
4561 return -errno;
4562
4563 if (r == 0)
4564 return 0;
4565
4566 return pollfd.revents;
4567}
4568
5a3ab509
LP
4569int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
4570 FILE *f;
4571 char *t;
4572 const char *fn;
4573 size_t k;
4574 int fd;
4575
4576 assert(path);
4577 assert(_f);
4578 assert(_temp_path);
4579
4580 t = new(char, strlen(path) + 1 + 6 + 1);
4581 if (!t)
4582 return -ENOMEM;
4583
9eb977db 4584 fn = path_get_file_name(path);
5a3ab509
LP
4585 k = fn-path;
4586 memcpy(t, path, k);
4587 t[k] = '.';
4588 stpcpy(stpcpy(t+k+1, fn), "XXXXXX");
4589
4590 fd = mkostemp(t, O_WRONLY|O_CLOEXEC);
4591 if (fd < 0) {
4592 free(t);
4593 return -errno;
4594 }
4595
4596 f = fdopen(fd, "we");
4597 if (!f) {
4598 unlink(t);
4599 free(t);
4600 return -errno;
4601 }
4602
4603 *_f = f;
4604 *_temp_path = t;
4605
4606 return 0;
4607}
4608
6ea832a2 4609int terminal_vhangup_fd(int fd) {
5a3ab509
LP
4610 assert(fd >= 0);
4611
6ea832a2
LP
4612 if (ioctl(fd, TIOCVHANGUP) < 0)
4613 return -errno;
4614
4615 return 0;
4616}
4617
4618int terminal_vhangup(const char *name) {
4619 int fd, r;
4620
4621 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
4622 if (fd < 0)
4623 return fd;
4624
4625 r = terminal_vhangup_fd(fd);
4626 close_nointr_nofail(fd);
4627
4628 return r;
4629}
4630
4631int vt_disallocate(const char *name) {
4632 int fd, r;
4633 unsigned u;
6ea832a2
LP
4634
4635 /* Deallocate the VT if possible. If not possible
4636 * (i.e. because it is the active one), at least clear it
4637 * entirely (including the scrollback buffer) */
4638
b83bc4e9
LP
4639 if (!startswith(name, "/dev/"))
4640 return -EINVAL;
4641
4642 if (!tty_is_vc(name)) {
4643 /* So this is not a VT. I guess we cannot deallocate
4644 * it then. But let's at least clear the screen */
4645
4646 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
4647 if (fd < 0)
4648 return fd;
4649
8585357a
LP
4650 loop_write(fd,
4651 "\033[r" /* clear scrolling region */
4652 "\033[H" /* move home */
4653 "\033[2J", /* clear screen */
4654 10, false);
b83bc4e9
LP
4655 close_nointr_nofail(fd);
4656
4657 return 0;
4658 }
6ea832a2
LP
4659
4660 if (!startswith(name, "/dev/tty"))
4661 return -EINVAL;
4662
4663 r = safe_atou(name+8, &u);
4664 if (r < 0)
4665 return r;
4666
4667 if (u <= 0)
b83bc4e9 4668 return -EINVAL;
6ea832a2 4669
b83bc4e9 4670 /* Try to deallocate */
6ea832a2
LP
4671 fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
4672 if (fd < 0)
4673 return fd;
4674
4675 r = ioctl(fd, VT_DISALLOCATE, u);
b83bc4e9 4676 close_nointr_nofail(fd);
6ea832a2 4677
b83bc4e9
LP
4678 if (r >= 0)
4679 return 0;
6ea832a2 4680
b83bc4e9 4681 if (errno != EBUSY)
6ea832a2 4682 return -errno;
6ea832a2 4683
b83bc4e9
LP
4684 /* Couldn't deallocate, so let's clear it fully with
4685 * scrollback */
4686 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
6ea832a2 4687 if (fd < 0)
b83bc4e9 4688 return fd;
6ea832a2 4689
8585357a
LP
4690 loop_write(fd,
4691 "\033[r" /* clear scrolling region */
4692 "\033[H" /* move home */
4693 "\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */
4694 10, false);
b83bc4e9 4695 close_nointr_nofail(fd);
6ea832a2 4696
b83bc4e9 4697 return 0;
6ea832a2
LP
4698}
4699
34ca941c
LP
4700int copy_file(const char *from, const char *to) {
4701 int r, fdf, fdt;
4702
4703 assert(from);
4704 assert(to);
4705
4706 fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY);
4707 if (fdf < 0)
4708 return -errno;
4709
4710 fdt = open(to, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY, 0644);
4711 if (fdt < 0) {
4712 close_nointr_nofail(fdf);
4713 return -errno;
4714 }
4715
4716 for (;;) {
4717 char buf[PIPE_BUF];
4718 ssize_t n, k;
4719
4720 n = read(fdf, buf, sizeof(buf));
4721 if (n < 0) {
4722 r = -errno;
4723
4724 close_nointr_nofail(fdf);
4725 close_nointr(fdt);
4726 unlink(to);
4727
4728 return r;
4729 }
4730
4731 if (n == 0)
4732 break;
4733
4734 errno = 0;
4735 k = loop_write(fdt, buf, n, false);
4736 if (n != k) {
4737 r = k < 0 ? k : (errno ? -errno : -EIO);
4738
4739 close_nointr_nofail(fdf);
4740 close_nointr(fdt);
4741
4742 unlink(to);
4743 return r;
4744 }
4745 }
4746
4747 close_nointr_nofail(fdf);
4748 r = close_nointr(fdt);
4749
4750 if (r < 0) {
4751 unlink(to);
4752 return r;
4753 }
4754
4755 return 0;
4756}
4757
4758int symlink_or_copy(const char *from, const char *to) {
4759 char *pf = NULL, *pt = NULL;
4760 struct stat a, b;
4761 int r;
4762
4763 assert(from);
4764 assert(to);
4765
9eb977db
KS
4766 if (path_get_parent(from, &pf) < 0 ||
4767 path_get_parent(to, &pt) < 0) {
34ca941c
LP
4768 r = -ENOMEM;
4769 goto finish;
4770 }
4771
4772 if (stat(pf, &a) < 0 ||
4773 stat(pt, &b) < 0) {
4774 r = -errno;
4775 goto finish;
4776 }
4777
4778 if (a.st_dev != b.st_dev) {
4779 free(pf);
4780 free(pt);
4781
4782 return copy_file(from, to);
4783 }
4784
4785 if (symlink(from, to) < 0) {
4786 r = -errno;
4787 goto finish;
4788 }
4789
4790 r = 0;
4791
4792finish:
4793 free(pf);
4794 free(pt);
4795
4796 return r;
4797}
4798
4799int symlink_or_copy_atomic(const char *from, const char *to) {
4800 char *t, *x;
4801 const char *fn;
4802 size_t k;
4803 unsigned long long ull;
4804 unsigned i;
4805 int r;
4806
4807 assert(from);
4808 assert(to);
4809
4810 t = new(char, strlen(to) + 1 + 16 + 1);
4811 if (!t)
4812 return -ENOMEM;
4813
9eb977db 4814 fn = path_get_file_name(to);
34ca941c
LP
4815 k = fn-to;
4816 memcpy(t, to, k);
4817 t[k] = '.';
4818 x = stpcpy(t+k+1, fn);
4819
4820 ull = random_ull();
4821 for (i = 0; i < 16; i++) {
4822 *(x++) = hexchar(ull & 0xF);
4823 ull >>= 4;
4824 }
4825
4826 *x = 0;
4827
4828 r = symlink_or_copy(from, t);
4829 if (r < 0) {
4830 unlink(t);
4831 free(t);
4832 return r;
4833 }
4834
4835 if (rename(t, to) < 0) {
4836 r = -errno;
4837 unlink(t);
4838 free(t);
4839 return r;
4840 }
4841
4842 free(t);
4843 return r;
4844}
4845
4d6d6518
LP
4846bool display_is_local(const char *display) {
4847 assert(display);
4848
4849 return
4850 display[0] == ':' &&
4851 display[1] >= '0' &&
4852 display[1] <= '9';
4853}
4854
4855int socket_from_display(const char *display, char **path) {
4856 size_t k;
4857 char *f, *c;
4858
4859 assert(display);
4860 assert(path);
4861
4862 if (!display_is_local(display))
4863 return -EINVAL;
4864
4865 k = strspn(display+1, "0123456789");
4866
4867 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
4868 if (!f)
4869 return -ENOMEM;
4870
4871 c = stpcpy(f, "/tmp/.X11-unix/X");
4872 memcpy(c, display+1, k);
4873 c[k] = 0;
4874
4875 *path = f;
4876
4877 return 0;
4878}
4879
1cccf435
MV
4880int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home) {
4881 struct passwd *p;
ddd88763 4882 uid_t u;
1cccf435
MV
4883
4884 assert(username);
4885 assert(*username);
1cccf435
MV
4886
4887 /* We enforce some special rules for uid=0: in order to avoid
4888 * NSS lookups for root we hardcode its data. */
4889
4890 if (streq(*username, "root") || streq(*username, "0")) {
4891 *username = "root";
4b67834e
LP
4892
4893 if (uid)
4894 *uid = 0;
4895
4896 if (gid)
4897 *gid = 0;
4898
4899 if (home)
4900 *home = "/root";
1cccf435
MV
4901 return 0;
4902 }
4903
ddd88763 4904 if (parse_uid(*username, &u) >= 0) {
1cccf435 4905 errno = 0;
ddd88763 4906 p = getpwuid(u);
1cccf435
MV
4907
4908 /* If there are multiple users with the same id, make
4909 * sure to leave $USER to the configured value instead
4910 * of the first occurrence in the database. However if
4911 * the uid was configured by a numeric uid, then let's
4912 * pick the real username from /etc/passwd. */
4913 if (p)
4914 *username = p->pw_name;
4915 } else {
4916 errno = 0;
4917 p = getpwnam(*username);
4918 }
4919
4920 if (!p)
4921 return errno != 0 ? -errno : -ESRCH;
4922
4b67834e
LP
4923 if (uid)
4924 *uid = p->pw_uid;
4925
4926 if (gid)
4927 *gid = p->pw_gid;
4928
4929 if (home)
4930 *home = p->pw_dir;
4931
4932 return 0;
4933}
4934
4935int get_group_creds(const char **groupname, gid_t *gid) {
4936 struct group *g;
4937 gid_t id;
4938
4939 assert(groupname);
4940
4941 /* We enforce some special rules for gid=0: in order to avoid
4942 * NSS lookups for root we hardcode its data. */
4943
4944 if (streq(*groupname, "root") || streq(*groupname, "0")) {
4945 *groupname = "root";
4946
4947 if (gid)
4948 *gid = 0;
4949
4950 return 0;
4951 }
4952
4953 if (parse_gid(*groupname, &id) >= 0) {
4954 errno = 0;
4955 g = getgrgid(id);
4956
4957 if (g)
4958 *groupname = g->gr_name;
4959 } else {
4960 errno = 0;
4961 g = getgrnam(*groupname);
4962 }
4963
4964 if (!g)
4965 return errno != 0 ? -errno : -ESRCH;
4966
4967 if (gid)
4968 *gid = g->gr_gid;
4969
1cccf435
MV
4970 return 0;
4971}
4972
43673799
LP
4973int in_group(const char *name) {
4974 gid_t gid, *gids;
4975 int ngroups_max, r, i;
4976
4977 r = get_group_creds(&name, &gid);
4978 if (r < 0)
4979 return r;
4980
4981 if (getgid() == gid)
4982 return 1;
4983
4984 if (getegid() == gid)
4985 return 1;
4986
4987 ngroups_max = sysconf(_SC_NGROUPS_MAX);
4988 assert(ngroups_max > 0);
4989
4990 gids = alloca(sizeof(gid_t) * ngroups_max);
4991
4992 r = getgroups(ngroups_max, gids);
4993 if (r < 0)
4994 return -errno;
4995
4996 for (i = 0; i < r; i++)
4997 if (gids[i] == gid)
4998 return 1;
4999
5000 return 0;
5001}
5002
8092a428
LP
5003int glob_exists(const char *path) {
5004 glob_t g;
5005 int r, k;
5006
5007 assert(path);
5008
5009 zero(g);
5010 errno = 0;
5011 k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
5012
5013 if (k == GLOB_NOMATCH)
5014 r = 0;
5015 else if (k == GLOB_NOSPACE)
5016 r = -ENOMEM;
5017 else if (k == 0)
5018 r = !strv_isempty(g.gl_pathv);
5019 else
5020 r = errno ? -errno : -EIO;
5021
5022 globfree(&g);
5023
5024 return r;
5025}
5026
83096483
LP
5027int dirent_ensure_type(DIR *d, struct dirent *de) {
5028 struct stat st;
5029
5030 assert(d);
5031 assert(de);
5032
5033 if (de->d_type != DT_UNKNOWN)
5034 return 0;
5035
5036 if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
5037 return -errno;
5038
5039 de->d_type =
5040 S_ISREG(st.st_mode) ? DT_REG :
5041 S_ISDIR(st.st_mode) ? DT_DIR :
5042 S_ISLNK(st.st_mode) ? DT_LNK :
5043 S_ISFIFO(st.st_mode) ? DT_FIFO :
5044 S_ISSOCK(st.st_mode) ? DT_SOCK :
5045 S_ISCHR(st.st_mode) ? DT_CHR :
5046 S_ISBLK(st.st_mode) ? DT_BLK :
5047 DT_UNKNOWN;
5048
5049 return 0;
5050}
5051
5052int in_search_path(const char *path, char **search) {
5053 char **i, *parent;
5054 int r;
5055
9eb977db 5056 r = path_get_parent(path, &parent);
83096483
LP
5057 if (r < 0)
5058 return r;
5059
5060 r = 0;
5061
5062 STRV_FOREACH(i, search) {
5063 if (path_equal(parent, *i)) {
5064 r = 1;
5065 break;
5066 }
5067 }
5068
5069 free(parent);
5070
5071 return r;
5072}
5073
034a2a52
LP
5074int get_files_in_directory(const char *path, char ***list) {
5075 DIR *d;
5076 int r = 0;
5077 unsigned n = 0;
5078 char **l = NULL;
5079
5080 assert(path);
d60ef526
LP
5081
5082 /* Returns all files in a directory in *list, and the number
5083 * of files as return value. If list is NULL returns only the
5084 * number */
034a2a52
LP
5085
5086 d = opendir(path);
8ea913b2
LP
5087 if (!d)
5088 return -errno;
5089
034a2a52
LP
5090 for (;;) {
5091 struct dirent buffer, *de;
5092 int k;
5093
5094 k = readdir_r(d, &buffer, &de);
5095 if (k != 0) {
5096 r = -k;
5097 goto finish;
5098 }
5099
5100 if (!de)
5101 break;
5102
5103 dirent_ensure_type(d, de);
5104
5105 if (!dirent_is_file(de))
5106 continue;
5107
d60ef526
LP
5108 if (list) {
5109 if ((unsigned) r >= n) {
5110 char **t;
034a2a52 5111
d60ef526
LP
5112 n = MAX(16, 2*r);
5113 t = realloc(l, sizeof(char*) * n);
5114 if (!t) {
5115 r = -ENOMEM;
5116 goto finish;
5117 }
034a2a52 5118
d60ef526
LP
5119 l = t;
5120 }
034a2a52 5121
d60ef526 5122 assert((unsigned) r < n);
034a2a52 5123
d60ef526
LP
5124 l[r] = strdup(de->d_name);
5125 if (!l[r]) {
5126 r = -ENOMEM;
5127 goto finish;
5128 }
034a2a52 5129
d60ef526
LP
5130 l[++r] = NULL;
5131 } else
5132 r++;
034a2a52
LP
5133 }
5134
5135finish:
5136 if (d)
5137 closedir(d);
5138
d60ef526
LP
5139 if (r >= 0) {
5140 if (list)
5141 *list = l;
5142 } else
034a2a52
LP
5143 strv_free(l);
5144
5145 return r;
5146}
5147
911a4828
LP
5148char *join(const char *x, ...) {
5149 va_list ap;
5150 size_t l;
5151 char *r, *p;
5152
5153 va_start(ap, x);
5154
5155 if (x) {
5156 l = strlen(x);
5157
5158 for (;;) {
5159 const char *t;
5160
5161 t = va_arg(ap, const char *);
5162 if (!t)
5163 break;
5164
5165 l += strlen(t);
5166 }
5167 } else
5168 l = 0;
5169
5170 va_end(ap);
5171
5172 r = new(char, l+1);
5173 if (!r)
5174 return NULL;
5175
5176 if (x) {
5177 p = stpcpy(r, x);
5178
5179 va_start(ap, x);
5180
5181 for (;;) {
5182 const char *t;
5183
5184 t = va_arg(ap, const char *);
5185 if (!t)
5186 break;
5187
5188 p = stpcpy(p, t);
5189 }
8ea913b2
LP
5190
5191 va_end(ap);
911a4828
LP
5192 } else
5193 r[0] = 0;
5194
5195 return r;
5196}
5197
b636465b
LP
5198bool is_main_thread(void) {
5199 static __thread int cached = 0;
5200
5201 if (_unlikely_(cached == 0))
5202 cached = getpid() == gettid() ? 1 : -1;
5203
5204 return cached > 0;
5205}
5206
94959f0f
LP
5207int block_get_whole_disk(dev_t d, dev_t *ret) {
5208 char *p, *s;
5209 int r;
5210 unsigned n, m;
5211
5212 assert(ret);
5213
5214 /* If it has a queue this is good enough for us */
5215 if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0)
5216 return -ENOMEM;
5217
5218 r = access(p, F_OK);
5219 free(p);
5220
5221 if (r >= 0) {
5222 *ret = d;
5223 return 0;
5224 }
5225
5226 /* If it is a partition find the originating device */
5227 if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0)
5228 return -ENOMEM;
5229
5230 r = access(p, F_OK);
5231 free(p);
5232
5233 if (r < 0)
5234 return -ENOENT;
5235
5236 /* Get parent dev_t */
5237 if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0)
5238 return -ENOMEM;
5239
5240 r = read_one_line_file(p, &s);
5241 free(p);
5242
5243 if (r < 0)
5244 return r;
5245
5246 r = sscanf(s, "%u:%u", &m, &n);
5247 free(s);
5248
5249 if (r != 2)
5250 return -EINVAL;
5251
5252 /* Only return this if it is really good enough for us. */
5253 if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0)
5254 return -ENOMEM;
5255
5256 r = access(p, F_OK);
5257 free(p);
5258
5259 if (r >= 0) {
5260 *ret = makedev(m, n);
5261 return 0;
5262 }
5263
5264 return -ENOENT;
5265}
5266
8d53b453 5267int file_is_priv_sticky(const char *p) {
ad293f5a
LP
5268 struct stat st;
5269
5270 assert(p);
5271
5272 if (lstat(p, &st) < 0)
5273 return -errno;
5274
5275 return
8d53b453 5276 (st.st_uid == 0 || st.st_uid == getuid()) &&
ad293f5a
LP
5277 (st.st_mode & S_ISVTX);
5278}
94959f0f 5279
f41607a6
LP
5280static const char *const ioprio_class_table[] = {
5281 [IOPRIO_CLASS_NONE] = "none",
5282 [IOPRIO_CLASS_RT] = "realtime",
5283 [IOPRIO_CLASS_BE] = "best-effort",
5284 [IOPRIO_CLASS_IDLE] = "idle"
5285};
5286
5287DEFINE_STRING_TABLE_LOOKUP(ioprio_class, int);
5288
5289static const char *const sigchld_code_table[] = {
5290 [CLD_EXITED] = "exited",
5291 [CLD_KILLED] = "killed",
5292 [CLD_DUMPED] = "dumped",
5293 [CLD_TRAPPED] = "trapped",
5294 [CLD_STOPPED] = "stopped",
5295 [CLD_CONTINUED] = "continued",
5296};
5297
5298DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
5299
5300static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = {
5301 [LOG_FAC(LOG_KERN)] = "kern",
5302 [LOG_FAC(LOG_USER)] = "user",
5303 [LOG_FAC(LOG_MAIL)] = "mail",
5304 [LOG_FAC(LOG_DAEMON)] = "daemon",
5305 [LOG_FAC(LOG_AUTH)] = "auth",
5306 [LOG_FAC(LOG_SYSLOG)] = "syslog",
5307 [LOG_FAC(LOG_LPR)] = "lpr",
5308 [LOG_FAC(LOG_NEWS)] = "news",
5309 [LOG_FAC(LOG_UUCP)] = "uucp",
5310 [LOG_FAC(LOG_CRON)] = "cron",
5311 [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
5312 [LOG_FAC(LOG_FTP)] = "ftp",
5313 [LOG_FAC(LOG_LOCAL0)] = "local0",
5314 [LOG_FAC(LOG_LOCAL1)] = "local1",
5315 [LOG_FAC(LOG_LOCAL2)] = "local2",
5316 [LOG_FAC(LOG_LOCAL3)] = "local3",
5317 [LOG_FAC(LOG_LOCAL4)] = "local4",
5318 [LOG_FAC(LOG_LOCAL5)] = "local5",
5319 [LOG_FAC(LOG_LOCAL6)] = "local6",
5320 [LOG_FAC(LOG_LOCAL7)] = "local7"
5321};
5322
5323DEFINE_STRING_TABLE_LOOKUP(log_facility_unshifted, int);
5324
5325static const char *const log_level_table[] = {
5326 [LOG_EMERG] = "emerg",
5327 [LOG_ALERT] = "alert",
5328 [LOG_CRIT] = "crit",
5329 [LOG_ERR] = "err",
5330 [LOG_WARNING] = "warning",
5331 [LOG_NOTICE] = "notice",
5332 [LOG_INFO] = "info",
5333 [LOG_DEBUG] = "debug"
5334};
5335
5336DEFINE_STRING_TABLE_LOOKUP(log_level, int);
5337
5338static const char* const sched_policy_table[] = {
5339 [SCHED_OTHER] = "other",
5340 [SCHED_BATCH] = "batch",
5341 [SCHED_IDLE] = "idle",
5342 [SCHED_FIFO] = "fifo",
5343 [SCHED_RR] = "rr"
5344};
5345
5346DEFINE_STRING_TABLE_LOOKUP(sched_policy, int);
5347
5348static const char* const rlimit_table[] = {
5349 [RLIMIT_CPU] = "LimitCPU",
5350 [RLIMIT_FSIZE] = "LimitFSIZE",
5351 [RLIMIT_DATA] = "LimitDATA",
5352 [RLIMIT_STACK] = "LimitSTACK",
5353 [RLIMIT_CORE] = "LimitCORE",
5354 [RLIMIT_RSS] = "LimitRSS",
5355 [RLIMIT_NOFILE] = "LimitNOFILE",
5356 [RLIMIT_AS] = "LimitAS",
5357 [RLIMIT_NPROC] = "LimitNPROC",
5358 [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
5359 [RLIMIT_LOCKS] = "LimitLOCKS",
5360 [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
5361 [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
5362 [RLIMIT_NICE] = "LimitNICE",
5363 [RLIMIT_RTPRIO] = "LimitRTPRIO",
5364 [RLIMIT_RTTIME] = "LimitRTTIME"
5365};
5366
5367DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
5368
5369static const char* const ip_tos_table[] = {
5370 [IPTOS_LOWDELAY] = "low-delay",
5371 [IPTOS_THROUGHPUT] = "throughput",
5372 [IPTOS_RELIABILITY] = "reliability",
5373 [IPTOS_LOWCOST] = "low-cost",
5374};
5375
5376DEFINE_STRING_TABLE_LOOKUP(ip_tos, int);
5377
4e240ab0 5378static const char *const __signal_table[] = {
f41607a6
LP
5379 [SIGHUP] = "HUP",
5380 [SIGINT] = "INT",
5381 [SIGQUIT] = "QUIT",
5382 [SIGILL] = "ILL",
5383 [SIGTRAP] = "TRAP",
5384 [SIGABRT] = "ABRT",
5385 [SIGBUS] = "BUS",
5386 [SIGFPE] = "FPE",
5387 [SIGKILL] = "KILL",
5388 [SIGUSR1] = "USR1",
5389 [SIGSEGV] = "SEGV",
5390 [SIGUSR2] = "USR2",
5391 [SIGPIPE] = "PIPE",
5392 [SIGALRM] = "ALRM",
5393 [SIGTERM] = "TERM",
5394#ifdef SIGSTKFLT
5395 [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */
5396#endif
5397 [SIGCHLD] = "CHLD",
5398 [SIGCONT] = "CONT",
5399 [SIGSTOP] = "STOP",
5400 [SIGTSTP] = "TSTP",
5401 [SIGTTIN] = "TTIN",
5402 [SIGTTOU] = "TTOU",
5403 [SIGURG] = "URG",
5404 [SIGXCPU] = "XCPU",
5405 [SIGXFSZ] = "XFSZ",
5406 [SIGVTALRM] = "VTALRM",
5407 [SIGPROF] = "PROF",
5408 [SIGWINCH] = "WINCH",
5409 [SIGIO] = "IO",
5410 [SIGPWR] = "PWR",
5411 [SIGSYS] = "SYS"
5412};
5413
4e240ab0
MS
5414DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
5415
5416const char *signal_to_string(int signo) {
5417 static __thread char buf[12];
5418 const char *name;
5419
5420 name = __signal_to_string(signo);
5421 if (name)
5422 return name;
5423
5424 if (signo >= SIGRTMIN && signo <= SIGRTMAX)
5425 snprintf(buf, sizeof(buf) - 1, "RTMIN+%d", signo - SIGRTMIN);
5426 else
5427 snprintf(buf, sizeof(buf) - 1, "%d", signo);
5428 char_array_0(buf);
5429 return buf;
5430}
5431
5432int signal_from_string(const char *s) {
5433 int signo;
5434 int offset = 0;
5435 unsigned u;
5436
5437 signo =__signal_from_string(s);
5438 if (signo > 0)
5439 return signo;
5440
5441 if (startswith(s, "RTMIN+")) {
5442 s += 6;
5443 offset = SIGRTMIN;
5444 }
5445 if (safe_atou(s, &u) >= 0) {
5446 signo = (int) u + offset;
5447 if (signo > 0 && signo < _NSIG)
5448 return signo;
5449 }
5450 return -1;
5451}
65457142
FC
5452
5453bool kexec_loaded(void) {
5454 bool loaded = false;
5455 char *s;
5456
5457 if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) {
5458 if (s[0] == '1')
5459 loaded = true;
5460 free(s);
5461 }
5462 return loaded;
5463}
fb9de93d
LP
5464
5465int strdup_or_null(const char *a, char **b) {
5466 char *c;
5467
5468 assert(b);
5469
5470 if (!a) {
5471 *b = NULL;
5472 return 0;
5473 }
5474
5475 c = strdup(a);
5476 if (!c)
5477 return -ENOMEM;
5478
5479 *b = c;
5480 return 0;
5481}
64685e0c 5482
87d2c1ff
LP
5483int prot_from_flags(int flags) {
5484
5485 switch (flags & O_ACCMODE) {
5486
5487 case O_RDONLY:
5488 return PROT_READ;
5489
5490 case O_WRONLY:
5491 return PROT_WRITE;
5492
5493 case O_RDWR:
5494 return PROT_READ|PROT_WRITE;
5495
5496 default:
5497 return -EINVAL;
5498 }
7c99e0c1 5499}
689b9a22 5500
babfc091 5501char *format_bytes(char *buf, size_t l, off_t t) {
c0f99c21 5502 unsigned i;
babfc091
LP
5503
5504 static const struct {
5505 const char *suffix;
5506 off_t factor;
5507 } table[] = {
32895bb3
LP
5508 { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
5509 { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
babfc091
LP
5510 { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
5511 { "G", 1024ULL*1024ULL*1024ULL },
5512 { "M", 1024ULL*1024ULL },
5513 { "K", 1024ULL },
5514 };
5515
5516 for (i = 0; i < ELEMENTSOF(table); i++) {
5517
5518 if (t >= table[i].factor) {
5519 snprintf(buf, l,
5520 "%llu.%llu%s",
5521 (unsigned long long) (t / table[i].factor),
5522 (unsigned long long) (((t*10ULL) / table[i].factor) % 10ULL),
5523 table[i].suffix);
5524
5525 goto finish;
5526 }
5527 }
5528
5529 snprintf(buf, l, "%lluB", (unsigned long long) t);
5530
5531finish:
5532 buf[l-1] = 0;
5533 return buf;
5534
5535}
55d7bfc1
LP
5536
5537void* memdup(const void *p, size_t l) {
5538 void *r;
5539
5540 assert(p);
5541
5542 r = malloc(l);
5543 if (!r)
5544 return NULL;
5545
5546 memcpy(r, p, l);
5547 return r;
5548}
bb99a35a
LP
5549
5550int fd_inc_sndbuf(int fd, size_t n) {
5551 int r, value;
5552 socklen_t l = sizeof(value);
5553
5554 r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
5555 if (r >= 0 &&
5556 l == sizeof(value) &&
5557 (size_t) value >= n*2)
5558 return 0;
5559
5560 value = (int) n;
5561 r = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value));
5562 if (r < 0)
5563 return -errno;
5564
5565 return 1;
5566}
5567
5568int fd_inc_rcvbuf(int fd, size_t n) {
5569 int r, value;
5570 socklen_t l = sizeof(value);
5571
5572 r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l);
5573 if (r >= 0 &&
5574 l == sizeof(value) &&
5575 (size_t) value >= n*2)
5576 return 0;
5577
5578 value = (int) n;
5579 r = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value));
5580 if (r < 0)
5581 return -errno;
5582
5583 return 1;
5584}
6bb92a16 5585
9bdc770c 5586int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
6bb92a16
LP
5587 pid_t parent_pid, agent_pid;
5588 int fd;
5589 bool stdout_is_tty, stderr_is_tty;
5590 unsigned n, i;
5591 va_list ap;
5592 char **l;
5593
5594 assert(pid);
5595 assert(path);
5596
5597 parent_pid = getpid();
5598
5599 /* Spawns a temporary TTY agent, making sure it goes away when
5600 * we go away */
5601
5602 agent_pid = fork();
5603 if (agent_pid < 0)
5604 return -errno;
5605
5606 if (agent_pid != 0) {
5607 *pid = agent_pid;
5608 return 0;
5609 }
5610
5611 /* In the child:
5612 *
5613 * Make sure the agent goes away when the parent dies */
5614 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
5615 _exit(EXIT_FAILURE);
5616
5617 /* Check whether our parent died before we were able
5618 * to set the death signal */
5619 if (getppid() != parent_pid)
5620 _exit(EXIT_SUCCESS);
5621
5622 /* Don't leak fds to the agent */
9bdc770c 5623 close_all_fds(except, n_except);
6bb92a16
LP
5624
5625 stdout_is_tty = isatty(STDOUT_FILENO);
5626 stderr_is_tty = isatty(STDERR_FILENO);
5627
5628 if (!stdout_is_tty || !stderr_is_tty) {
5629 /* Detach from stdout/stderr. and reopen
5630 * /dev/tty for them. This is important to
5631 * ensure that when systemctl is started via
5632 * popen() or a similar call that expects to
5633 * read EOF we actually do generate EOF and
5634 * not delay this indefinitely by because we
5635 * keep an unused copy of stdin around. */
5636 fd = open("/dev/tty", O_WRONLY);
5637 if (fd < 0) {
5638 log_error("Failed to open /dev/tty: %m");
5639 _exit(EXIT_FAILURE);
5640 }
5641
5642 if (!stdout_is_tty)
5643 dup2(fd, STDOUT_FILENO);
5644
5645 if (!stderr_is_tty)
5646 dup2(fd, STDERR_FILENO);
5647
5648 if (fd > 2)
5649 close(fd);
5650 }
5651
5652 /* Count arguments */
5653 va_start(ap, path);
5654 for (n = 0; va_arg(ap, char*); n++)
5655 ;
5656 va_end(ap);
5657
5658 /* Allocate strv */
5659 l = alloca(sizeof(char *) * (n + 1));
5660
5661 /* Fill in arguments */
5662 va_start(ap, path);
5663 for (i = 0; i <= n; i++)
5664 l[i] = va_arg(ap, char*);
5665 va_end(ap);
5666
5667 execv(path, l);
5668 _exit(EXIT_FAILURE);
5669}
68faf98c
LP
5670
5671int setrlimit_closest(int resource, const struct rlimit *rlim) {
5672 struct rlimit highest, fixed;
5673
5674 assert(rlim);
5675
5676 if (setrlimit(resource, rlim) >= 0)
5677 return 0;
5678
5679 if (errno != EPERM)
5680 return -errno;
5681
5682 /* So we failed to set the desired setrlimit, then let's try
5683 * to get as close as we can */
5684 assert_se(getrlimit(resource, &highest) == 0);
5685
5686 fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max);
5687 fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max);
5688
5689 if (setrlimit(resource, &fixed) < 0)
5690 return -errno;
5691
5692 return 0;
5693}
3d9a4122 5694
ab94af92
LP
5695int getenv_for_pid(pid_t pid, const char *field, char **_value) {
5696 char path[sizeof("/proc/")-1+10+sizeof("/environ")], *value = NULL;
5697 int r;
5698 FILE *f;
5699 bool done = false;
5700 size_t l;
5701
5702 assert(field);
5703 assert(_value);
5704
5705 if (pid == 0)
5706 pid = getpid();
5707
5708 snprintf(path, sizeof(path), "/proc/%lu/environ", (unsigned long) pid);
5709 char_array_0(path);
5710
5711 f = fopen(path, "re");
5712 if (!f)
5713 return -errno;
5714
5715 l = strlen(field);
5716 r = 0;
5717
5718 do {
5719 char line[LINE_MAX];
5720 unsigned i;
5721
5722 for (i = 0; i < sizeof(line)-1; i++) {
5723 int c;
5724
5725 c = getc(f);
5726 if (_unlikely_(c == EOF)) {
5727 done = true;
5728 break;
5729 } else if (c == 0)
5730 break;
5731
5732 line[i] = c;
5733 }
5734 line[i] = 0;
5735
5736 if (memcmp(line, field, l) == 0 && line[l] == '=') {
5737 value = strdup(line + l + 1);
5738 if (!value) {
5739 r = -ENOMEM;
5740 break;
5741 }
5742
5743 r = 1;
5744 break;
5745 }
5746
5747 } while (!done);
5748
5749 fclose(f);
5750
5751 if (r >= 0)
5752 *_value = value;
5753
5754 return r;
5755}
d889a206
LP
5756
5757int can_sleep(const char *type) {
5758 char *p, *w, *state;
5759 size_t l, k;
5760 bool found = false;
5761 int r;
5762
5763 assert(type);
5764
5765 r = read_one_line_file("/sys/power/state", &p);
5766 if (r < 0)
5767 return r == -ENOENT ? 0 : r;
5768
5769 k = strlen(type);
5770
5771 FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state) {
5772 if (l == k && strncmp(w, type, l) == 0) {
5773 found = true;
5774 break;
5775 }
5776 }
5777
5778 free(p);
5779 return found;
5780}
49dbfa7b
LP
5781
5782bool is_valid_documentation_url(const char *url) {
5783 assert(url);
5784
5785 if (startswith(url, "http://") && url[7])
5786 return true;
5787
5788 if (startswith(url, "https://") && url[8])
5789 return true;
5790
5791 if (startswith(url, "file:") && url[5])
5792 return true;
5793
5794 if (startswith(url, "info:") && url[5])
5795 return true;
5796
5797 if (startswith(url, "man:") && url[4])
5798 return true;
5799
5800 return false;
5801}
9be346c9
HH
5802
5803bool in_initrd(void) {
8f33b5b8 5804 static int saved = -1;
825c6fe5 5805 struct statfs s;
8f33b5b8 5806
825c6fe5
LP
5807 if (saved >= 0)
5808 return saved;
5809
5810 /* We make two checks here:
5811 *
5812 * 1. the flag file /etc/initrd-release must exist
5813 * 2. the root file system must be a memory file system
5814 *
5815 * The second check is extra paranoia, since misdetecting an
5816 * initrd can have bad bad consequences due the initrd
5817 * emptying when transititioning to the main systemd.
5818 */
5819
5820 saved = access("/etc/initrd-release", F_OK) >= 0 &&
5821 statfs("/", &s) >= 0 &&
5822 (s.f_type == TMPFS_MAGIC || s.f_type == RAMFS_MAGIC);
9be346c9 5823
8f33b5b8 5824 return saved;
9be346c9 5825}
069cfc85
LP
5826
5827void warn_melody(void) {
5828 int fd;
5829
5830 fd = open("/dev/console", O_WRONLY|O_CLOEXEC|O_NOCTTY);
5831 if (fd < 0)
5832 return;
5833
5834 /* Yeah, this is synchronous. Kinda sucks. Bute well... */
5835
5836 ioctl(fd, KIOCSOUND, (int)(1193180/440));
5837 usleep(125*USEC_PER_MSEC);
5838
5839 ioctl(fd, KIOCSOUND, (int)(1193180/220));
5840 usleep(125*USEC_PER_MSEC);
5841
5842 ioctl(fd, KIOCSOUND, (int)(1193180/220));
5843 usleep(125*USEC_PER_MSEC);
5844
5845 ioctl(fd, KIOCSOUND, 0);
5846 close_nointr_nofail(fd);
5847}
cd3bd60a
LP
5848
5849int make_console_stdio(void) {
5850 int fd, r;
5851
5852 /* Make /dev/console the controlling terminal and stdin/stdout/stderr */
5853
5854 fd = acquire_terminal("/dev/console", false, true, true, (usec_t) -1);
5855 if (fd < 0) {
5856 log_error("Failed to acquire terminal: %s", strerror(-fd));
5857 return fd;
5858 }
5859
5860 r = make_stdio(fd);
5861 if (r < 0) {
5862 log_error("Failed to duplicate terminal fd: %s", strerror(-r));
5863 return r;
5864 }
5865
5866 return 0;
5867}