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