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