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