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