]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/util.c
util-lib: move take_password_lock() to user-util.[ch]
[thirdparty/systemd.git] / src / basic / 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
f6c2284a
LP
22#include <ctype.h>
23#include <dirent.h>
60918275 24#include <errno.h>
f6c2284a
LP
25#include <fcntl.h>
26#include <glob.h>
27#include <grp.h>
28#include <langinfo.h>
20f56fdd 29#include <libintl.h>
f6c2284a
LP
30#include <limits.h>
31#include <linux/magic.h>
257b0719 32#include <linux/oom.h>
ef886c6a 33#include <linux/sched.h>
f6c2284a 34#include <locale.h>
0a6f50c0 35#include <poll.h>
ef2f1067 36#include <pwd.h>
f6c2284a
LP
37#include <sched.h>
38#include <signal.h>
39#include <stdarg.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <sys/file.h>
44#include <sys/ioctl.h>
87d2c1ff 45#include <sys/mman.h>
6d313367 46#include <sys/mount.h>
6afc95b7 47#include <sys/personality.h>
f6c2284a
LP
48#include <sys/prctl.h>
49#include <sys/resource.h>
50#include <sys/stat.h>
abe4aa14 51#include <sys/statvfs.h>
f6c2284a
LP
52#include <sys/time.h>
53#include <sys/types.h>
54#include <sys/utsname.h>
55#include <sys/vfs.h>
56#include <sys/wait.h>
57#include <sys/xattr.h>
58#include <syslog.h>
59#include <unistd.h>
eef46c37
LP
60
61/* When we include libgen.h because we need dirname() we immediately
f6c2284a
LP
62 * undefine basename() since libgen.h defines it as a macro to the
63 * POSIX version which is really broken. We prefer GNU basename(). */
eef46c37 64#include <libgen.h>
2b6bf07d 65#undef basename
60918275 66
9bf3b535
LP
67#ifdef HAVE_SYS_AUXV_H
68#include <sys/auxv.h>
69#endif
70
f6c2284a
LP
71/* We include linux/fs.h as last of the system headers, as it
72 * otherwise conflicts with sys/mount.h. Yay, Linux is great! */
73#include <linux/fs.h>
74
3f6fd1ba 75#include "build.h"
f6c2284a
LP
76#include "def.h"
77#include "device-nodes.h"
78#include "env-util.h"
4f5dd394 79#include "escape.h"
f6c2284a 80#include "exit-status.h"
3ffd4af2 81#include "fd-util.h"
f6c2284a
LP
82#include "fileio.h"
83#include "formats-util.h"
84#include "gunicode.h"
85#include "hashmap.h"
86#include "hostname-util.h"
1dccbe19 87#include "ioprio.h"
a9f5d454 88#include "log.h"
f6c2284a
LP
89#include "macro.h"
90#include "missing.h"
c38dfac9 91#include "mkdir.h"
e4e73a63 92#include "hexdecoct.h"
6bedfcbb 93#include "parse-util.h"
9eb977db 94#include "path-util.h"
0b452006 95#include "process-util.h"
3df3e884 96#include "random-util.h"
24882e06 97#include "signal-util.h"
f6c2284a 98#include "sparse-endian.h"
07630cea 99#include "string-util.h"
f6c2284a
LP
100#include "strv.h"
101#include "terminal-util.h"
b1d4f8e1 102#include "user-util.h"
f6c2284a 103#include "utf8.h"
4f5dd394 104#include "util.h"
3ffd4af2 105#include "virt.h"
56cf987f 106
012d7b42
ZJS
107/* Put this test here for a lack of better place */
108assert_cc(EAGAIN == EWOULDBLOCK);
109
9a0e6896
LP
110int saved_argc = 0;
111char **saved_argv = NULL;
9086e840 112
37f85e66 113size_t page_size(void) {
ec202eae 114 static thread_local size_t pgsz = 0;
37f85e66 115 long r;
116
87d2c1ff 117 if (_likely_(pgsz > 0))
37f85e66 118 return pgsz;
119
e67f47e5
LP
120 r = sysconf(_SC_PAGESIZE);
121 assert(r > 0);
37f85e66 122
123 pgsz = (size_t) r;
37f85e66 124 return pgsz;
125}
126
4b73a0c0
LP
127int unlink_noerrno(const char *path) {
128 PROTECT_ERRNO;
129 int r;
130
131 r = unlink(path);
132 if (r < 0)
133 return -errno;
134
135 return 0;
136}
137
34ca941c
LP
138int fchmod_umask(int fd, mode_t m) {
139 mode_t u;
140 int r;
141
142 u = umask(0777);
143 r = fchmod(fd, m & (~u)) < 0 ? -errno : 0;
144 umask(u);
145
146 return r;
147}
148
849958d1 149int readlinkat_malloc(int fd, const char *p, char **ret) {
87f0e418 150 size_t l = 100;
2d2ebd6b 151 int r;
87f0e418
LP
152
153 assert(p);
2d2ebd6b 154 assert(ret);
87f0e418
LP
155
156 for (;;) {
157 char *c;
158 ssize_t n;
159
2d2ebd6b
LP
160 c = new(char, l);
161 if (!c)
87f0e418
LP
162 return -ENOMEM;
163
849958d1 164 n = readlinkat(fd, p, c, l-1);
2d2ebd6b
LP
165 if (n < 0) {
166 r = -errno;
87f0e418 167 free(c);
2d2ebd6b 168 return r;
87f0e418
LP
169 }
170
171 if ((size_t) n < l-1) {
172 c[n] = 0;
2d2ebd6b 173 *ret = c;
87f0e418
LP
174 return 0;
175 }
176
177 free(c);
178 l *= 2;
179 }
180}
181
849958d1
LP
182int readlink_malloc(const char *p, char **ret) {
183 return readlinkat_malloc(AT_FDCWD, p, ret);
184}
185
9a67bcf2
TG
186int readlink_value(const char *p, char **ret) {
187 _cleanup_free_ char *link = NULL;
188 char *value;
189 int r;
190
191 r = readlink_malloc(p, &link);
192 if (r < 0)
193 return r;
194
195 value = basename(link);
196 if (!value)
197 return -ENOENT;
198
199 value = strdup(value);
200 if (!value)
201 return -ENOMEM;
202
203 *ret = value;
204
205 return 0;
206}
207
2c7108c4 208int readlink_and_make_absolute(const char *p, char **r) {
1058cbf2
ZJS
209 _cleanup_free_ char *target = NULL;
210 char *k;
2c7108c4
LP
211 int j;
212
213 assert(p);
214 assert(r);
215
1058cbf2
ZJS
216 j = readlink_malloc(p, &target);
217 if (j < 0)
2c7108c4
LP
218 return j;
219
220 k = file_in_same_dir(p, target);
2c7108c4
LP
221 if (!k)
222 return -ENOMEM;
223
224 *r = k;
225 return 0;
226}
227
83096483
LP
228int readlink_and_canonicalize(const char *p, char **r) {
229 char *t, *s;
230 int j;
231
232 assert(p);
233 assert(r);
234
235 j = readlink_and_make_absolute(p, &t);
236 if (j < 0)
237 return j;
238
239 s = canonicalize_file_name(t);
240 if (s) {
241 free(t);
242 *r = s;
243 } else
244 *r = t;
245
246 path_kill_slashes(*r);
247
248 return 0;
249}
250
4a72ff34 251char *file_in_same_dir(const char *path, const char *filename) {
ebd93cb6 252 char *e, *ret;
4a72ff34
LP
253 size_t k;
254
255 assert(path);
256 assert(filename);
257
258 /* This removes the last component of path and appends
259 * filename, unless the latter is absolute anyway or the
260 * former isn't */
261
262 if (path_is_absolute(filename))
263 return strdup(filename);
264
ebd93cb6
LP
265 e = strrchr(path, '/');
266 if (!e)
4a72ff34
LP
267 return strdup(filename);
268
269 k = strlen(filename);
ebd93cb6
LP
270 ret = new(char, (e + 1 - path) + k + 1);
271 if (!ret)
4a72ff34
LP
272 return NULL;
273
ebd93cb6
LP
274 memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1);
275 return ret;
4a72ff34 276}
fb624d04 277
c32dd69b
LP
278int rmdir_parents(const char *path, const char *stop) {
279 size_t l;
280 int r = 0;
281
282 assert(path);
283 assert(stop);
284
285 l = strlen(path);
286
287 /* Skip trailing slashes */
288 while (l > 0 && path[l-1] == '/')
289 l--;
290
291 while (l > 0) {
292 char *t;
293
294 /* Skip last component */
295 while (l > 0 && path[l-1] != '/')
296 l--;
297
298 /* Skip trailing slashes */
299 while (l > 0 && path[l-1] == '/')
300 l--;
301
302 if (l <= 0)
303 break;
304
305 if (!(t = strndup(path, l)))
306 return -ENOMEM;
307
308 if (path_startswith(stop, t)) {
309 free(t);
310 return 0;
311 }
312
313 r = rmdir(t);
314 free(t);
315
316 if (r < 0)
317 if (errno != ENOENT)
318 return -errno;
319 }
320
321 return 0;
322}
323
a34bf9db 324_pure_ static bool hidden_file_allow_backup(const char *filename) {
c85dc17b
LP
325 assert(filename);
326
327 return
328 filename[0] == '.' ||
6c78be3c 329 streq(filename, "lost+found") ||
e472d476
LP
330 streq(filename, "aquota.user") ||
331 streq(filename, "aquota.group") ||
c85dc17b
LP
332 endswith(filename, ".rpmnew") ||
333 endswith(filename, ".rpmsave") ||
334 endswith(filename, ".rpmorig") ||
335 endswith(filename, ".dpkg-old") ||
336 endswith(filename, ".dpkg-new") ||
0cdfd26e 337 endswith(filename, ".dpkg-tmp") ||
c7088e49
MP
338 endswith(filename, ".dpkg-dist") ||
339 endswith(filename, ".dpkg-bak") ||
340 endswith(filename, ".dpkg-backup") ||
341 endswith(filename, ".dpkg-remove") ||
c85dc17b
LP
342 endswith(filename, ".swp");
343}
344
a34bf9db 345bool hidden_file(const char *filename) {
a228a22f
LP
346 assert(filename);
347
348 if (endswith(filename, "~"))
93f1a063 349 return true;
a228a22f 350
a34bf9db 351 return hidden_file_allow_backup(filename);
a228a22f
LP
352}
353
42856c10 354bool fstype_is_network(const char *fstype) {
a05f97b3 355 static const char table[] =
ba89821c 356 "afs\0"
a05f97b3
LP
357 "cifs\0"
358 "smbfs\0"
da92ca5e 359 "sshfs\0"
a05f97b3 360 "ncpfs\0"
dac70dc7 361 "ncp\0"
a05f97b3
LP
362 "nfs\0"
363 "nfs4\0"
364 "gfs\0"
67608cad
LP
365 "gfs2\0"
366 "glusterfs\0";
367
368 const char *x;
369
370 x = startswith(fstype, "fuse.");
371 if (x)
372 fstype = x;
42856c10 373
a05f97b3 374 return nulstr_contains(table, fstype);
42856c10
LP
375}
376
8407a5d0
LP
377bool is_device_path(const char *path) {
378
379 /* Returns true on paths that refer to a device, either in
380 * sysfs or in /dev */
381
382 return
383 path_startswith(path, "/dev/") ||
384 path_startswith(path, "/sys/");
385}
386
01f78473 387int dir_is_empty(const char *path) {
a05f97b3 388 _cleanup_closedir_ DIR *d;
ac7edd91 389 struct dirent *de;
01f78473 390
a05f97b3
LP
391 d = opendir(path);
392 if (!d)
01f78473
LP
393 return -errno;
394
ac7edd91
LP
395 FOREACH_DIRENT(de, d, return -errno)
396 return 0;
01f78473 397
ac7edd91 398 return 1;
01f78473
LP
399}
400
5b6319dc
LP
401void rename_process(const char name[8]) {
402 assert(name);
403
5d6b1584
LP
404 /* This is a like a poor man's setproctitle(). It changes the
405 * comm field, argv[0], and also the glibc's internally used
406 * name of the process. For the first one a limit of 16 chars
407 * applies, to the second one usually one of 10 (i.e. length
408 * of "/sbin/init"), to the third one one of 7 (i.e. length of
409 * "systemd"). If you pass a longer string it will be
410 * truncated */
5b6319dc 411
5d6b1584 412 prctl(PR_SET_NAME, name);
5b6319dc
LP
413
414 if (program_invocation_name)
415 strncpy(program_invocation_name, name, strlen(program_invocation_name));
9a0e6896
LP
416
417 if (saved_argc > 0) {
418 int i;
419
420 if (saved_argv[0])
421 strncpy(saved_argv[0], name, strlen(saved_argv[0]));
422
423 for (i = 1; i < saved_argc; i++) {
424 if (!saved_argv[i])
425 break;
426
29804cc1 427 memzero(saved_argv[i], strlen(saved_argv[i]));
9a0e6896
LP
428 }
429 }
5b6319dc
LP
430}
431
d1678248 432bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
943aad8c 433 assert(s);
d1678248
ILG
434 assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
435
436 return F_TYPE_EQUAL(s->f_type, magic_value);
437}
438
439int fd_check_fstype(int fd, statfs_f_type_t magic_value) {
440 struct statfs s;
441
442 if (fstatfs(fd, &s) < 0)
443 return -errno;
73020ab2 444
d1678248
ILG
445 return is_fs_type(&s, magic_value);
446}
447
448int path_check_fstype(const char *path, statfs_f_type_t magic_value) {
449 _cleanup_close_ int fd = -1;
450
451 fd = open(path, O_RDONLY);
452 if (fd < 0)
453 return -errno;
454
455 return fd_check_fstype(fd, magic_value);
456}
457
458bool is_temporary_fs(const struct statfs *s) {
459 return is_fs_type(s, TMPFS_MAGIC) ||
460 is_fs_type(s, RAMFS_MAGIC);
943aad8c
ZJS
461}
462
c6878637 463int fd_is_temporary_fs(int fd) {
979ef53a
DR
464 struct statfs s;
465
466 if (fstatfs(fd, &s) < 0)
467 return -errno;
468
469 return is_temporary_fs(&s);
470}
471
8c6db833
LP
472int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
473 assert(path);
474
475 /* Under the assumption that we are running privileged we
476 * first change the access mode and only then hand out
477 * ownership to avoid a window where access is too open. */
478
fed1e721 479 if (mode != MODE_INVALID)
8d53b453
LP
480 if (chmod(path, mode) < 0)
481 return -errno;
8c6db833 482
fed1e721 483 if (uid != UID_INVALID || gid != GID_INVALID)
8d53b453
LP
484 if (chown(path, uid, gid) < 0)
485 return -errno;
8c6db833
LP
486
487 return 0;
ef2f1067
LP
488}
489
f4b47811
LP
490int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) {
491 assert(fd >= 0);
492
493 /* Under the assumption that we are running privileged we
494 * first change the access mode and only then hand out
495 * ownership to avoid a window where access is too open. */
496
fed1e721 497 if (mode != MODE_INVALID)
9588bc32
LP
498 if (fchmod(fd, mode) < 0)
499 return -errno;
f4b47811 500
fed1e721 501 if (uid != UID_INVALID || gid != GID_INVALID)
9588bc32
LP
502 if (fchown(fd, uid, gid) < 0)
503 return -errno;
f4b47811
LP
504
505 return 0;
506}
507
9d9951a4
HH
508int files_same(const char *filea, const char *fileb) {
509 struct stat a, b;
b4f10a5e 510
9d9951a4 511 if (stat(filea, &a) < 0)
b4f10a5e
LP
512 return -errno;
513
9d9951a4 514 if (stat(fileb, &b) < 0)
b4f10a5e
LP
515 return -errno;
516
9d9951a4
HH
517 return a.st_dev == b.st_dev &&
518 a.st_ino == b.st_ino;
519}
520
521int running_in_chroot(void) {
522 int ret;
523
524 ret = files_same("/proc/1/root", "/");
525 if (ret < 0)
526 return ret;
527
528 return ret == 0;
b4f10a5e
LP
529}
530
c38dfac9 531int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
03e334a1 532 _cleanup_close_ int fd;
c38dfac9 533 int r;
f6144808
LP
534
535 assert(path);
536
c38dfac9
KS
537 if (parents)
538 mkdir_parents(path, 0755);
73836c5c 539
c38dfac9 540 fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644);
73836c5c 541 if (fd < 0)
f6144808
LP
542 return -errno;
543
c38dfac9
KS
544 if (mode > 0) {
545 r = fchmod(fd, mode);
546 if (r < 0)
547 return -errno;
548 }
549
fed1e721 550 if (uid != UID_INVALID || gid != GID_INVALID) {
c38dfac9
KS
551 r = fchown(fd, uid, gid);
552 if (r < 0)
553 return -errno;
554 }
555
3a43da28 556 if (stamp != USEC_INFINITY) {
c38dfac9
KS
557 struct timespec ts[2];
558
559 timespec_store(&ts[0], stamp);
359efc59 560 ts[1] = ts[0];
c38dfac9
KS
561 r = futimens(fd, ts);
562 } else
563 r = futimens(fd, NULL);
564 if (r < 0)
565 return -errno;
566
f6144808
LP
567 return 0;
568}
afea26ad 569
c38dfac9 570int touch(const char *path) {
fed1e721 571 return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, 0);
c38dfac9
KS
572}
573
919ce0b7 574noreturn void freeze(void) {
720ce21d
LP
575
576 /* Make sure nobody waits for us on a socket anymore */
577 close_all_fds(NULL, 0);
578
c29597a1
LP
579 sync();
580
3c14d26c
LP
581 for (;;)
582 pause();
583}
584
00dc5d76
LP
585bool null_or_empty(struct stat *st) {
586 assert(st);
587
588 if (S_ISREG(st->st_mode) && st->st_size <= 0)
589 return true;
590
c8f26f42 591 if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
00dc5d76
LP
592 return true;
593
594 return false;
595}
596
83096483
LP
597int null_or_empty_path(const char *fn) {
598 struct stat st;
599
600 assert(fn);
601
602 if (stat(fn, &st) < 0)
603 return -errno;
604
605 return null_or_empty(&st);
606}
607
ed88bcfb
ZJS
608int null_or_empty_fd(int fd) {
609 struct stat st;
610
611 assert(fd >= 0);
612
613 if (fstat(fd, &st) < 0)
614 return -errno;
615
616 return null_or_empty(&st);
617}
618
87d2c1ff 619bool dirent_is_file(const struct dirent *de) {
fb19a739
LP
620 assert(de);
621
a34bf9db 622 if (hidden_file(de->d_name))
fb19a739
LP
623 return false;
624
625 if (de->d_type != DT_REG &&
626 de->d_type != DT_LNK &&
627 de->d_type != DT_UNKNOWN)
628 return false;
629
630 return true;
631}
632
87d2c1ff
LP
633bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) {
634 assert(de);
635
a228a22f
LP
636 if (de->d_type != DT_REG &&
637 de->d_type != DT_LNK &&
638 de->d_type != DT_UNKNOWN)
639 return false;
640
a34bf9db 641 if (hidden_file_allow_backup(de->d_name))
87d2c1ff
LP
642 return false;
643
644 return endswith(de->d_name, suffix);
645}
646
e801700e 647static int do_execute(char **directories, usec_t timeout, char *argv[]) {
49681057 648 _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
e801700e
ZJS
649 _cleanup_set_free_free_ Set *seen = NULL;
650 char **directory;
83cc030f 651
49681057
ZJS
652 /* We fork this all off from a child process so that we can
653 * somewhat cleanly make use of SIGALRM to set a time limit */
83cc030f 654
ce30c8dc
LP
655 (void) reset_all_signal_handlers();
656 (void) reset_signal_mask();
83cc030f 657
49681057 658 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
83cc030f 659
49681057
ZJS
660 pids = hashmap_new(NULL);
661 if (!pids)
662 return log_oom();
83cc030f 663
e801700e
ZJS
664 seen = set_new(&string_hash_ops);
665 if (!seen)
666 return log_oom();
83cc030f 667
e801700e
ZJS
668 STRV_FOREACH(directory, directories) {
669 _cleanup_closedir_ DIR *d;
670 struct dirent *de;
83cc030f 671
e801700e
ZJS
672 d = opendir(*directory);
673 if (!d) {
674 if (errno == ENOENT)
675 continue;
83cc030f 676
e801700e
ZJS
677 return log_error_errno(errno, "Failed to open directory %s: %m", *directory);
678 }
83cc030f 679
e801700e
ZJS
680 FOREACH_DIRENT(de, d, break) {
681 _cleanup_free_ char *path = NULL;
682 pid_t pid;
683 int r;
684
685 if (!dirent_is_file(de))
686 continue;
83cc030f 687
e801700e
ZJS
688 if (set_contains(seen, de->d_name)) {
689 log_debug("%1$s/%2$s skipped (%2$s was already seen).", *directory, de->d_name);
690 continue;
691 }
692
693 r = set_put_strdup(seen, de->d_name);
694 if (r < 0)
695 return log_oom();
696
697 path = strjoin(*directory, "/", de->d_name, NULL);
698 if (!path)
699 return log_oom();
700
701 if (null_or_empty_path(path)) {
702 log_debug("%s is empty (a mask).", path);
703 continue;
7034e9db 704 }
83cc030f 705
e801700e
ZJS
706 pid = fork();
707 if (pid < 0) {
708 log_error_errno(errno, "Failed to fork: %m");
709 continue;
710 } else if (pid == 0) {
711 char *_argv[2];
83cc030f 712
e801700e 713 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
83cc030f 714
e801700e
ZJS
715 if (!argv) {
716 _argv[0] = path;
717 _argv[1] = NULL;
718 argv = _argv;
719 } else
720 argv[0] = path;
721
722 execv(path, argv);
723 return log_error_errno(errno, "Failed to execute %s: %m", path);
724 }
725
726 log_debug("Spawned %s as " PID_FMT ".", path, pid);
83cc030f 727
e801700e
ZJS
728 r = hashmap_put(pids, UINT_TO_PTR(pid), path);
729 if (r < 0)
730 return log_oom();
731 path = NULL;
732 }
49681057 733 }
83cc030f 734
49681057
ZJS
735 /* Abort execution of this process after the timout. We simply
736 * rely on SIGALRM as default action terminating the process,
737 * and turn on alarm(). */
83cc030f 738
49681057
ZJS
739 if (timeout != USEC_INFINITY)
740 alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
83cc030f 741
49681057
ZJS
742 while (!hashmap_isempty(pids)) {
743 _cleanup_free_ char *path = NULL;
744 pid_t pid;
aa62a893 745
49681057
ZJS
746 pid = PTR_TO_UINT(hashmap_first_key(pids));
747 assert(pid > 0);
83cc030f 748
49681057
ZJS
749 path = hashmap_remove(pids, UINT_TO_PTR(pid));
750 assert(path);
aa62a893 751
49681057
ZJS
752 wait_for_terminate_and_warn(path, pid, true);
753 }
aa62a893 754
49681057
ZJS
755 return 0;
756}
aa62a893 757
e801700e 758void execute_directories(const char* const* directories, usec_t timeout, char *argv[]) {
49681057
ZJS
759 pid_t executor_pid;
760 int r;
e801700e
ZJS
761 char *name;
762 char **dirs = (char**) directories;
763
764 assert(!strv_isempty(dirs));
83cc030f 765
e801700e
ZJS
766 name = basename(dirs[0]);
767 assert(!isempty(name));
aa62a893 768
e801700e
ZJS
769 /* Executes all binaries in the directories in parallel and waits
770 * for them to finish. Optionally a timeout is applied. If a file
771 * with the same name exists in more than one directory, the
772 * earliest one wins. */
83cc030f 773
49681057
ZJS
774 executor_pid = fork();
775 if (executor_pid < 0) {
776 log_error_errno(errno, "Failed to fork: %m");
777 return;
778
779 } else if (executor_pid == 0) {
e801700e 780 r = do_execute(dirs, timeout, argv);
49681057 781 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
aa62a893 782 }
83cc030f 783
e801700e 784 wait_for_terminate_and_warn(name, executor_pid, true);
83cc030f
LP
785}
786
a88c8750
TG
787bool plymouth_running(void) {
788 return access("/run/plymouth/pid", F_OK) >= 0;
789}
790
424a19f8 791int symlink_atomic(const char *from, const char *to) {
2e78fa79 792 _cleanup_free_ char *t = NULL;
ae6c3cc0 793 int r;
34ca941c
LP
794
795 assert(from);
796 assert(to);
797
14bcf25c 798 r = tempfn_random(to, NULL, &t);
ae6c3cc0
LP
799 if (r < 0)
800 return r;
34ca941c 801
424a19f8
LP
802 if (symlink(from, t) < 0)
803 return -errno;
34ca941c
LP
804
805 if (rename(t, to) < 0) {
2e78fa79
LP
806 unlink_noerrno(t);
807 return -errno;
34ca941c
LP
808 }
809
424a19f8 810 return 0;
34ca941c
LP
811}
812
875e1014
ILG
813int symlink_idempotent(const char *from, const char *to) {
814 _cleanup_free_ char *p = NULL;
815 int r;
816
817 assert(from);
818 assert(to);
819
820 if (symlink(from, to) < 0) {
821 if (errno != EEXIST)
822 return -errno;
823
824 r = readlink_malloc(to, &p);
825 if (r < 0)
826 return r;
827
828 if (!streq(p, from))
829 return -EINVAL;
830 }
831
832 return 0;
833}
834
1554afae
LP
835int mknod_atomic(const char *path, mode_t mode, dev_t dev) {
836 _cleanup_free_ char *t = NULL;
ae6c3cc0 837 int r;
1554afae
LP
838
839 assert(path);
840
14bcf25c 841 r = tempfn_random(path, NULL, &t);
ae6c3cc0
LP
842 if (r < 0)
843 return r;
1554afae
LP
844
845 if (mknod(t, mode, dev) < 0)
846 return -errno;
847
848 if (rename(t, path) < 0) {
849 unlink_noerrno(t);
850 return -errno;
851 }
852
853 return 0;
854}
855
856int mkfifo_atomic(const char *path, mode_t mode) {
857 _cleanup_free_ char *t = NULL;
ae6c3cc0 858 int r;
1554afae
LP
859
860 assert(path);
861
14bcf25c 862 r = tempfn_random(path, NULL, &t);
ae6c3cc0
LP
863 if (r < 0)
864 return r;
1554afae
LP
865
866 if (mkfifo(t, mode) < 0)
867 return -errno;
868
869 if (rename(t, path) < 0) {
870 unlink_noerrno(t);
871 return -errno;
872 }
873
874 return 0;
875}
876
4d6d6518
LP
877bool display_is_local(const char *display) {
878 assert(display);
879
880 return
881 display[0] == ':' &&
882 display[1] >= '0' &&
883 display[1] <= '9';
884}
885
886int socket_from_display(const char *display, char **path) {
887 size_t k;
888 char *f, *c;
889
890 assert(display);
891 assert(path);
892
893 if (!display_is_local(display))
894 return -EINVAL;
895
896 k = strspn(display+1, "0123456789");
897
f8294e41 898 f = new(char, strlen("/tmp/.X11-unix/X") + k + 1);
4d6d6518
LP
899 if (!f)
900 return -ENOMEM;
901
902 c = stpcpy(f, "/tmp/.X11-unix/X");
903 memcpy(c, display+1, k);
904 c[k] = 0;
905
906 *path = f;
907
908 return 0;
909}
910
8092a428 911int glob_exists(const char *path) {
7fd1b19b 912 _cleanup_globfree_ glob_t g = {};
8d98da3f 913 int k;
8092a428
LP
914
915 assert(path);
916
8092a428
LP
917 errno = 0;
918 k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
919
920 if (k == GLOB_NOMATCH)
8d98da3f 921 return 0;
8092a428 922 else if (k == GLOB_NOSPACE)
8d98da3f 923 return -ENOMEM;
8092a428 924 else if (k == 0)
8d98da3f 925 return !strv_isempty(g.gl_pathv);
8092a428 926 else
8d98da3f
ZJS
927 return errno ? -errno : -EIO;
928}
8092a428 929
8d98da3f
ZJS
930int glob_extend(char ***strv, const char *path) {
931 _cleanup_globfree_ glob_t g = {};
932 int k;
933 char **p;
934
935 errno = 0;
a8ccacf5 936 k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
8d98da3f
ZJS
937
938 if (k == GLOB_NOMATCH)
939 return -ENOENT;
940 else if (k == GLOB_NOSPACE)
941 return -ENOMEM;
942 else if (k != 0 || strv_isempty(g.gl_pathv))
943 return errno ? -errno : -EIO;
944
945 STRV_FOREACH(p, g.gl_pathv) {
946 k = strv_extend(strv, *p);
947 if (k < 0)
948 break;
949 }
950
951 return k;
8092a428
LP
952}
953
83096483
LP
954int dirent_ensure_type(DIR *d, struct dirent *de) {
955 struct stat st;
956
957 assert(d);
958 assert(de);
959
960 if (de->d_type != DT_UNKNOWN)
961 return 0;
962
963 if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
964 return -errno;
965
966 de->d_type =
967 S_ISREG(st.st_mode) ? DT_REG :
968 S_ISDIR(st.st_mode) ? DT_DIR :
969 S_ISLNK(st.st_mode) ? DT_LNK :
970 S_ISFIFO(st.st_mode) ? DT_FIFO :
971 S_ISSOCK(st.st_mode) ? DT_SOCK :
972 S_ISCHR(st.st_mode) ? DT_CHR :
973 S_ISBLK(st.st_mode) ? DT_BLK :
974 DT_UNKNOWN;
975
976 return 0;
977}
978
034a2a52 979int get_files_in_directory(const char *path, char ***list) {
893fa014
ZJS
980 _cleanup_closedir_ DIR *d = NULL;
981 size_t bufsize = 0, n = 0;
982 _cleanup_strv_free_ char **l = NULL;
034a2a52
LP
983
984 assert(path);
d60ef526
LP
985
986 /* Returns all files in a directory in *list, and the number
987 * of files as return value. If list is NULL returns only the
893fa014 988 * number. */
034a2a52
LP
989
990 d = opendir(path);
8ea913b2
LP
991 if (!d)
992 return -errno;
993
034a2a52 994 for (;;) {
7d5e9c0f 995 struct dirent *de;
034a2a52 996
3fd11280
FW
997 errno = 0;
998 de = readdir(d);
999 if (!de && errno != 0)
1000 return -errno;
034a2a52
LP
1001 if (!de)
1002 break;
1003
1004 dirent_ensure_type(d, de);
1005
1006 if (!dirent_is_file(de))
1007 continue;
1008
d60ef526 1009 if (list) {
893fa014
ZJS
1010 /* one extra slot is needed for the terminating NULL */
1011 if (!GREEDY_REALLOC(l, bufsize, n + 2))
1012 return -ENOMEM;
034a2a52 1013
893fa014
ZJS
1014 l[n] = strdup(de->d_name);
1015 if (!l[n])
1016 return -ENOMEM;
034a2a52 1017
893fa014 1018 l[++n] = NULL;
d60ef526 1019 } else
893fa014 1020 n++;
034a2a52
LP
1021 }
1022
893fa014
ZJS
1023 if (list) {
1024 *list = l;
1025 l = NULL; /* avoid freeing */
1026 }
034a2a52 1027
893fa014 1028 return n;
034a2a52
LP
1029}
1030
b636465b 1031bool is_main_thread(void) {
ec202eae 1032 static thread_local int cached = 0;
b636465b
LP
1033
1034 if (_unlikely_(cached == 0))
1035 cached = getpid() == gettid() ? 1 : -1;
1036
1037 return cached > 0;
1038}
1039
94959f0f
LP
1040int block_get_whole_disk(dev_t d, dev_t *ret) {
1041 char *p, *s;
1042 int r;
1043 unsigned n, m;
1044
1045 assert(ret);
1046
1047 /* If it has a queue this is good enough for us */
1048 if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0)
1049 return -ENOMEM;
1050
1051 r = access(p, F_OK);
1052 free(p);
1053
1054 if (r >= 0) {
1055 *ret = d;
1056 return 0;
1057 }
1058
1059 /* If it is a partition find the originating device */
1060 if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0)
1061 return -ENOMEM;
1062
1063 r = access(p, F_OK);
1064 free(p);
1065
1066 if (r < 0)
1067 return -ENOENT;
1068
1069 /* Get parent dev_t */
1070 if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0)
1071 return -ENOMEM;
1072
1073 r = read_one_line_file(p, &s);
1074 free(p);
1075
1076 if (r < 0)
1077 return r;
1078
1079 r = sscanf(s, "%u:%u", &m, &n);
1080 free(s);
1081
1082 if (r != 2)
1083 return -EINVAL;
1084
1085 /* Only return this if it is really good enough for us. */
1086 if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0)
1087 return -ENOMEM;
1088
1089 r = access(p, F_OK);
1090 free(p);
1091
1092 if (r >= 0) {
1093 *ret = makedev(m, n);
1094 return 0;
1095 }
1096
1097 return -ENOENT;
1098}
1099
f41607a6
LP
1100static const char *const ioprio_class_table[] = {
1101 [IOPRIO_CLASS_NONE] = "none",
1102 [IOPRIO_CLASS_RT] = "realtime",
1103 [IOPRIO_CLASS_BE] = "best-effort",
1104 [IOPRIO_CLASS_IDLE] = "idle"
1105};
1106
f8b69d1d 1107DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX);
f41607a6
LP
1108
1109static const char *const sigchld_code_table[] = {
1110 [CLD_EXITED] = "exited",
1111 [CLD_KILLED] = "killed",
1112 [CLD_DUMPED] = "dumped",
1113 [CLD_TRAPPED] = "trapped",
1114 [CLD_STOPPED] = "stopped",
1115 [CLD_CONTINUED] = "continued",
1116};
1117
1118DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
1119
1120static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = {
1121 [LOG_FAC(LOG_KERN)] = "kern",
1122 [LOG_FAC(LOG_USER)] = "user",
1123 [LOG_FAC(LOG_MAIL)] = "mail",
1124 [LOG_FAC(LOG_DAEMON)] = "daemon",
1125 [LOG_FAC(LOG_AUTH)] = "auth",
1126 [LOG_FAC(LOG_SYSLOG)] = "syslog",
1127 [LOG_FAC(LOG_LPR)] = "lpr",
1128 [LOG_FAC(LOG_NEWS)] = "news",
1129 [LOG_FAC(LOG_UUCP)] = "uucp",
1130 [LOG_FAC(LOG_CRON)] = "cron",
1131 [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
1132 [LOG_FAC(LOG_FTP)] = "ftp",
1133 [LOG_FAC(LOG_LOCAL0)] = "local0",
1134 [LOG_FAC(LOG_LOCAL1)] = "local1",
1135 [LOG_FAC(LOG_LOCAL2)] = "local2",
1136 [LOG_FAC(LOG_LOCAL3)] = "local3",
1137 [LOG_FAC(LOG_LOCAL4)] = "local4",
1138 [LOG_FAC(LOG_LOCAL5)] = "local5",
1139 [LOG_FAC(LOG_LOCAL6)] = "local6",
1140 [LOG_FAC(LOG_LOCAL7)] = "local7"
1141};
1142
f8b69d1d 1143DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0));
f41607a6 1144
adb8ec96
EV
1145bool log_facility_unshifted_is_valid(int facility) {
1146 return facility >= 0 && facility <= LOG_FAC(~0);
1147}
1148
f41607a6
LP
1149static const char *const log_level_table[] = {
1150 [LOG_EMERG] = "emerg",
1151 [LOG_ALERT] = "alert",
1152 [LOG_CRIT] = "crit",
1153 [LOG_ERR] = "err",
1154 [LOG_WARNING] = "warning",
1155 [LOG_NOTICE] = "notice",
1156 [LOG_INFO] = "info",
1157 [LOG_DEBUG] = "debug"
1158};
1159
f8b69d1d 1160DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG);
f41607a6 1161
adb8ec96
EV
1162bool log_level_is_valid(int level) {
1163 return level >= 0 && level <= LOG_DEBUG;
1164}
1165
f41607a6
LP
1166static const char* const sched_policy_table[] = {
1167 [SCHED_OTHER] = "other",
1168 [SCHED_BATCH] = "batch",
1169 [SCHED_IDLE] = "idle",
1170 [SCHED_FIFO] = "fifo",
1171 [SCHED_RR] = "rr"
1172};
1173
f8b69d1d 1174DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
f41607a6 1175
517d56b1 1176static const char* const rlimit_table[_RLIMIT_MAX] = {
f41607a6
LP
1177 [RLIMIT_CPU] = "LimitCPU",
1178 [RLIMIT_FSIZE] = "LimitFSIZE",
1179 [RLIMIT_DATA] = "LimitDATA",
1180 [RLIMIT_STACK] = "LimitSTACK",
1181 [RLIMIT_CORE] = "LimitCORE",
1182 [RLIMIT_RSS] = "LimitRSS",
1183 [RLIMIT_NOFILE] = "LimitNOFILE",
1184 [RLIMIT_AS] = "LimitAS",
1185 [RLIMIT_NPROC] = "LimitNPROC",
1186 [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
1187 [RLIMIT_LOCKS] = "LimitLOCKS",
1188 [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
1189 [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
1190 [RLIMIT_NICE] = "LimitNICE",
1191 [RLIMIT_RTPRIO] = "LimitRTPRIO",
1192 [RLIMIT_RTTIME] = "LimitRTTIME"
1193};
1194
1195DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
1196
65457142
FC
1197bool kexec_loaded(void) {
1198 bool loaded = false;
1199 char *s;
1200
1201 if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) {
1202 if (s[0] == '1')
1203 loaded = true;
1204 free(s);
1205 }
1206 return loaded;
1207}
fb9de93d 1208
87d2c1ff
LP
1209int prot_from_flags(int flags) {
1210
1211 switch (flags & O_ACCMODE) {
1212
1213 case O_RDONLY:
1214 return PROT_READ;
1215
1216 case O_WRONLY:
1217 return PROT_WRITE;
1218
1219 case O_RDWR:
1220 return PROT_READ|PROT_WRITE;
1221
1222 default:
1223 return -EINVAL;
1224 }
7c99e0c1 1225}
689b9a22 1226
55d7bfc1
LP
1227void* memdup(const void *p, size_t l) {
1228 void *r;
1229
1230 assert(p);
1231
1232 r = malloc(l);
1233 if (!r)
1234 return NULL;
1235
1236 memcpy(r, p, l);
1237 return r;
1238}
bb99a35a 1239
9bdc770c 1240int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
6bb92a16 1241 bool stdout_is_tty, stderr_is_tty;
8a7c93d8
LP
1242 pid_t parent_pid, agent_pid;
1243 sigset_t ss, saved_ss;
6bb92a16
LP
1244 unsigned n, i;
1245 va_list ap;
1246 char **l;
1247
1248 assert(pid);
1249 assert(path);
1250
6bb92a16
LP
1251 /* Spawns a temporary TTY agent, making sure it goes away when
1252 * we go away */
1253
8a7c93d8
LP
1254 parent_pid = getpid();
1255
1256 /* First we temporarily block all signals, so that the new
1257 * child has them blocked initially. This way, we can be sure
1258 * that SIGTERMs are not lost we might send to the agent. */
1259 assert_se(sigfillset(&ss) >= 0);
1260 assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0);
1261
6bb92a16 1262 agent_pid = fork();
8a7c93d8
LP
1263 if (agent_pid < 0) {
1264 assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
6bb92a16 1265 return -errno;
8a7c93d8 1266 }
6bb92a16
LP
1267
1268 if (agent_pid != 0) {
8a7c93d8 1269 assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
6bb92a16
LP
1270 *pid = agent_pid;
1271 return 0;
1272 }
1273
1274 /* In the child:
1275 *
1276 * Make sure the agent goes away when the parent dies */
1277 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
1278 _exit(EXIT_FAILURE);
1279
8a7c93d8
LP
1280 /* Make sure we actually can kill the agent, if we need to, in
1281 * case somebody invoked us from a shell script that trapped
1282 * SIGTERM or so... */
ce30c8dc
LP
1283 (void) reset_all_signal_handlers();
1284 (void) reset_signal_mask();
8a7c93d8 1285
6bb92a16 1286 /* Check whether our parent died before we were able
8a7c93d8 1287 * to set the death signal and unblock the signals */
6bb92a16
LP
1288 if (getppid() != parent_pid)
1289 _exit(EXIT_SUCCESS);
1290
1291 /* Don't leak fds to the agent */
9bdc770c 1292 close_all_fds(except, n_except);
6bb92a16
LP
1293
1294 stdout_is_tty = isatty(STDOUT_FILENO);
1295 stderr_is_tty = isatty(STDERR_FILENO);
1296
1297 if (!stdout_is_tty || !stderr_is_tty) {
8a7c93d8
LP
1298 int fd;
1299
6bb92a16
LP
1300 /* Detach from stdout/stderr. and reopen
1301 * /dev/tty for them. This is important to
1302 * ensure that when systemctl is started via
1303 * popen() or a similar call that expects to
1304 * read EOF we actually do generate EOF and
1305 * not delay this indefinitely by because we
1306 * keep an unused copy of stdin around. */
1307 fd = open("/dev/tty", O_WRONLY);
1308 if (fd < 0) {
56f64d95 1309 log_error_errno(errno, "Failed to open /dev/tty: %m");
6bb92a16
LP
1310 _exit(EXIT_FAILURE);
1311 }
1312
1313 if (!stdout_is_tty)
1314 dup2(fd, STDOUT_FILENO);
1315
1316 if (!stderr_is_tty)
1317 dup2(fd, STDERR_FILENO);
1318
1319 if (fd > 2)
1320 close(fd);
1321 }
1322
1323 /* Count arguments */
1324 va_start(ap, path);
1325 for (n = 0; va_arg(ap, char*); n++)
1326 ;
1327 va_end(ap);
1328
1329 /* Allocate strv */
1330 l = alloca(sizeof(char *) * (n + 1));
1331
1332 /* Fill in arguments */
1333 va_start(ap, path);
1334 for (i = 0; i <= n; i++)
1335 l[i] = va_arg(ap, char*);
1336 va_end(ap);
1337
1338 execv(path, l);
1339 _exit(EXIT_FAILURE);
1340}
68faf98c
LP
1341
1342int setrlimit_closest(int resource, const struct rlimit *rlim) {
1343 struct rlimit highest, fixed;
1344
1345 assert(rlim);
1346
1347 if (setrlimit(resource, rlim) >= 0)
1348 return 0;
1349
1350 if (errno != EPERM)
1351 return -errno;
1352
1353 /* So we failed to set the desired setrlimit, then let's try
1354 * to get as close as we can */
1355 assert_se(getrlimit(resource, &highest) == 0);
1356
1357 fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max);
1358 fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max);
1359
1360 if (setrlimit(resource, &fixed) < 0)
1361 return -errno;
1362
1363 return 0;
1364}
3d9a4122 1365
3d7415f4
LP
1366bool http_etag_is_valid(const char *etag) {
1367 if (isempty(etag))
1368 return false;
1369
1370 if (!endswith(etag, "\""))
1371 return false;
1372
1373 if (!startswith(etag, "\"") && !startswith(etag, "W/\""))
1374 return false;
1375
1376 return true;
1377}
1378
a2e03378
LP
1379bool http_url_is_valid(const char *url) {
1380 const char *p;
49dbfa7b 1381
a2e03378
LP
1382 if (isempty(url))
1383 return false;
49dbfa7b 1384
a2e03378
LP
1385 p = startswith(url, "http://");
1386 if (!p)
1387 p = startswith(url, "https://");
1388 if (!p)
1389 return false;
49dbfa7b 1390
a2e03378
LP
1391 if (isempty(p))
1392 return false;
49dbfa7b 1393
a2e03378
LP
1394 return ascii_is_valid(p);
1395}
49dbfa7b 1396
a2e03378
LP
1397bool documentation_url_is_valid(const char *url) {
1398 const char *p;
1399
1400 if (isempty(url))
1401 return false;
1402
1403 if (http_url_is_valid(url))
49dbfa7b
LP
1404 return true;
1405
a2e03378
LP
1406 p = startswith(url, "file:/");
1407 if (!p)
1408 p = startswith(url, "info:");
1409 if (!p)
1410 p = startswith(url, "man:");
1411
1412 if (isempty(p))
1413 return false;
1414
1415 return ascii_is_valid(p);
49dbfa7b 1416}
9be346c9
HH
1417
1418bool in_initrd(void) {
73020ab2 1419 static int saved = -1;
825c6fe5 1420 struct statfs s;
8f33b5b8 1421
825c6fe5
LP
1422 if (saved >= 0)
1423 return saved;
1424
1425 /* We make two checks here:
1426 *
1427 * 1. the flag file /etc/initrd-release must exist
1428 * 2. the root file system must be a memory file system
1429 *
1430 * The second check is extra paranoia, since misdetecting an
1431 * initrd can have bad bad consequences due the initrd
1432 * emptying when transititioning to the main systemd.
1433 */
1434
1435 saved = access("/etc/initrd-release", F_OK) >= 0 &&
1436 statfs("/", &s) >= 0 &&
943aad8c 1437 is_temporary_fs(&s);
9be346c9 1438
8f33b5b8 1439 return saved;
9be346c9 1440}
069cfc85 1441
0b507b17
LP
1442bool string_is_safe(const char *p) {
1443 const char *t;
1444
6294aa76
LP
1445 if (!p)
1446 return false;
0b507b17
LP
1447
1448 for (t = p; *t; t++) {
01539d6e 1449 if (*t > 0 && *t < ' ')
0b507b17
LP
1450 return false;
1451
843f6bf4 1452 if (strchr("\\\"\'\x7f", *t))
0b507b17
LP
1453 return false;
1454 }
1455
1456 return true;
1457}
cfbc22ab 1458
a9e12476
KS
1459/* hey glibc, APIs with callbacks without a user pointer are so useless */
1460void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
1c574591 1461 int (*compar) (const void *, const void *, void *), void *arg) {
a9e12476
KS
1462 size_t l, u, idx;
1463 const void *p;
1464 int comparison;
1465
1466 l = 0;
1467 u = nmemb;
1468 while (l < u) {
1469 idx = (l + u) / 2;
1470 p = (void *)(((const char *) base) + (idx * size));
1471 comparison = compar(key, p, arg);
1472 if (comparison < 0)
1473 u = idx;
1474 else if (comparison > 0)
1475 l = idx + 1;
1476 else
1477 return (void *)p;
1478 }
1479 return NULL;
1480}
09017585 1481
20f56fdd
DR
1482void init_gettext(void) {
1483 setlocale(LC_ALL, "");
1484 textdomain(GETTEXT_PACKAGE);
1485}
1486
09017585
MS
1487bool is_locale_utf8(void) {
1488 const char *set;
1489 static int cached_answer = -1;
1490
1491 if (cached_answer >= 0)
1492 goto out;
1493
1494 if (!setlocale(LC_ALL, "")) {
1495 cached_answer = true;
1496 goto out;
1497 }
1498
1499 set = nl_langinfo(CODESET);
1500 if (!set) {
1501 cached_answer = true;
1502 goto out;
1503 }
1504
f168c273 1505 if (streq(set, "UTF-8")) {
fee79e01
HH
1506 cached_answer = true;
1507 goto out;
1508 }
1509
6cf2f1d9
HH
1510 /* For LC_CTYPE=="C" return true, because CTYPE is effectly
1511 * unset and everything can do to UTF-8 nowadays. */
fee79e01
HH
1512 set = setlocale(LC_CTYPE, NULL);
1513 if (!set) {
1514 cached_answer = true;
1515 goto out;
1516 }
1517
6cf2f1d9
HH
1518 /* Check result, but ignore the result if C was set
1519 * explicitly. */
1520 cached_answer =
9797f89b 1521 STR_IN_SET(set, "C", "POSIX") &&
6cf2f1d9
HH
1522 !getenv("LC_ALL") &&
1523 !getenv("LC_CTYPE") &&
1524 !getenv("LANG");
fee79e01 1525
09017585 1526out:
6cf2f1d9 1527 return (bool) cached_answer;
09017585 1528}
c339d977
MS
1529
1530const char *draw_special_char(DrawSpecialChar ch) {
1531 static const char *draw_table[2][_DRAW_SPECIAL_CHAR_MAX] = {
6b01f1d3 1532
c339d977 1533 /* UTF-8 */ {
6b01f1d3 1534 [DRAW_TREE_VERTICAL] = "\342\224\202 ", /* │ */
45a5ff0d
MS
1535 [DRAW_TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */
1536 [DRAW_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */
55c0b89c 1537 [DRAW_TREE_SPACE] = " ", /* */
6b01f1d3
LP
1538 [DRAW_TRIANGULAR_BULLET] = "\342\200\243", /* ‣ */
1539 [DRAW_BLACK_CIRCLE] = "\342\227\217", /* ● */
1540 [DRAW_ARROW] = "\342\206\222", /* → */
13f8b8cb 1541 [DRAW_DASH] = "\342\200\223", /* – */
c339d977 1542 },
6b01f1d3 1543
c339d977 1544 /* ASCII fallback */ {
6b01f1d3 1545 [DRAW_TREE_VERTICAL] = "| ",
45a5ff0d
MS
1546 [DRAW_TREE_BRANCH] = "|-",
1547 [DRAW_TREE_RIGHT] = "`-",
55c0b89c 1548 [DRAW_TREE_SPACE] = " ",
6b01f1d3
LP
1549 [DRAW_TRIANGULAR_BULLET] = ">",
1550 [DRAW_BLACK_CIRCLE] = "*",
1551 [DRAW_ARROW] = "->",
13f8b8cb 1552 [DRAW_DASH] = "-",
c339d977
MS
1553 }
1554 };
1555
1556 return draw_table[!is_locale_utf8()][ch];
1557}
409bc9c3 1558
240dbaa4
LP
1559int on_ac_power(void) {
1560 bool found_offline = false, found_online = false;
1561 _cleanup_closedir_ DIR *d = NULL;
1562
1563 d = opendir("/sys/class/power_supply");
1564 if (!d)
6d890034 1565 return errno == ENOENT ? true : -errno;
240dbaa4
LP
1566
1567 for (;;) {
1568 struct dirent *de;
240dbaa4
LP
1569 _cleanup_close_ int fd = -1, device = -1;
1570 char contents[6];
1571 ssize_t n;
240dbaa4 1572
3fd11280
FW
1573 errno = 0;
1574 de = readdir(d);
1575 if (!de && errno != 0)
1576 return -errno;
240dbaa4
LP
1577
1578 if (!de)
1579 break;
1580
a34bf9db 1581 if (hidden_file(de->d_name))
240dbaa4
LP
1582 continue;
1583
1584 device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
1585 if (device < 0) {
1586 if (errno == ENOENT || errno == ENOTDIR)
1587 continue;
1588
1589 return -errno;
1590 }
1591
1592 fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1593 if (fd < 0) {
1594 if (errno == ENOENT)
1595 continue;
1596
1597 return -errno;
1598 }
1599
1600 n = read(fd, contents, sizeof(contents));
1601 if (n < 0)
1602 return -errno;
1603
1604 if (n != 6 || memcmp(contents, "Mains\n", 6))
1605 continue;
1606
03e334a1 1607 safe_close(fd);
240dbaa4
LP
1608 fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1609 if (fd < 0) {
1610 if (errno == ENOENT)
1611 continue;
1612
1613 return -errno;
1614 }
1615
1616 n = read(fd, contents, sizeof(contents));
1617 if (n < 0)
1618 return -errno;
1619
1620 if (n != 2 || contents[1] != '\n')
1621 return -EIO;
1622
1623 if (contents[0] == '1') {
1624 found_online = true;
1625 break;
1626 } else if (contents[0] == '0')
1627 found_offline = true;
1628 else
1629 return -EIO;
1630 }
1631
1632 return found_online || !found_offline;
1633}
fabe5c0e 1634
ca2d3784
ZJS
1635void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
1636 size_t a, newalloc;
392d5b37
LP
1637 void *q;
1638
98088803 1639 assert(p);
e93c33d4
SL
1640 assert(allocated);
1641
392d5b37
LP
1642 if (*allocated >= need)
1643 return *p;
1644
ca2d3784
ZJS
1645 newalloc = MAX(need * 2, 64u / size);
1646 a = newalloc * size;
98088803
LP
1647
1648 /* check for overflows */
ca2d3784 1649 if (a < size * need)
98088803
LP
1650 return NULL;
1651
392d5b37
LP
1652 q = realloc(*p, a);
1653 if (!q)
1654 return NULL;
1655
1656 *p = q;
ca2d3784 1657 *allocated = newalloc;
392d5b37
LP
1658 return q;
1659}
aa96c6cb 1660
ca2d3784 1661void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) {
98088803 1662 size_t prev;
4545a231
DH
1663 uint8_t *q;
1664
98088803
LP
1665 assert(p);
1666 assert(allocated);
1667
1668 prev = *allocated;
1669
ca2d3784 1670 q = greedy_realloc(p, allocated, need, size);
4545a231
DH
1671 if (!q)
1672 return NULL;
1673
1674 if (*allocated > prev)
ca2d3784 1675 memzero(q + prev * size, (*allocated - prev) * size);
4545a231
DH
1676
1677 return q;
1678}
1679
aa96c6cb
LP
1680bool id128_is_valid(const char *s) {
1681 size_t i, l;
1682
1683 l = strlen(s);
1684 if (l == 32) {
1685
1686 /* Simple formatted 128bit hex string */
1687
1688 for (i = 0; i < l; i++) {
1689 char c = s[i];
1690
1691 if (!(c >= '0' && c <= '9') &&
1692 !(c >= 'a' && c <= 'z') &&
1693 !(c >= 'A' && c <= 'Z'))
1694 return false;
1695 }
1696
1697 } else if (l == 36) {
1698
1699 /* Formatted UUID */
1700
1701 for (i = 0; i < l; i++) {
1702 char c = s[i];
1703
1704 if ((i == 8 || i == 13 || i == 18 || i == 23)) {
1705 if (c != '-')
1706 return false;
1707 } else {
1708 if (!(c >= '0' && c <= '9') &&
1709 !(c >= 'a' && c <= 'z') &&
1710 !(c >= 'A' && c <= 'Z'))
1711 return false;
1712 }
1713 }
1714
1715 } else
1716 return false;
1717
1718 return true;
1719}
7085053a 1720
74df0fca 1721int shall_restore_state(void) {
1a299299 1722 _cleanup_free_ char *value = NULL;
74df0fca 1723 int r;
295edddf 1724
1a299299 1725 r = get_proc_cmdline_key("systemd.restore_state=", &value);
74df0fca
LP
1726 if (r < 0)
1727 return r;
1a299299
LP
1728 if (r == 0)
1729 return true;
295edddf 1730
1a299299 1731 return parse_boolean(value) != 0;
74df0fca
LP
1732}
1733
1734int proc_cmdline(char **ret) {
b5884878 1735 assert(ret);
295edddf 1736
75f86906 1737 if (detect_container() > 0)
b5884878
LP
1738 return get_process_cmdline(1, 0, false, ret);
1739 else
1740 return read_one_line_file("/proc/cmdline", ret);
295edddf 1741}
bc9fd78c 1742
059cb385 1743int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
141a79f4 1744 _cleanup_free_ char *line = NULL;
f32d2db1 1745 const char *p;
141a79f4
ZJS
1746 int r;
1747
059cb385
LP
1748 assert(parse_item);
1749
141a79f4
ZJS
1750 r = proc_cmdline(&line);
1751 if (r < 0)
b5884878 1752 return r;
141a79f4 1753
f32d2db1
LP
1754 p = line;
1755 for (;;) {
1756 _cleanup_free_ char *word = NULL;
1757 char *value = NULL;
141a79f4 1758
12ba2c44 1759 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
f32d2db1
LP
1760 if (r < 0)
1761 return r;
1762 if (r == 0)
1763 break;
141a79f4 1764
059cb385
LP
1765 /* Filter out arguments that are intended only for the
1766 * initrd */
1767 if (!in_initrd() && startswith(word, "rd."))
1768 continue;
1769
1770 value = strchr(word, '=');
1771 if (value)
1772 *(value++) = 0;
1773
1774 r = parse_item(word, value);
1775 if (r < 0)
141a79f4 1776 return r;
141a79f4
ZJS
1777 }
1778
1779 return 0;
1780}
1781
1a299299
LP
1782int get_proc_cmdline_key(const char *key, char **value) {
1783 _cleanup_free_ char *line = NULL, *ret = NULL;
1784 bool found = false;
1785 const char *p;
1786 int r;
1787
1788 assert(key);
1789
1790 r = proc_cmdline(&line);
1791 if (r < 0)
1792 return r;
1793
1794 p = line;
1795 for (;;) {
1796 _cleanup_free_ char *word = NULL;
1797 const char *e;
1798
12ba2c44 1799 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
1a299299
LP
1800 if (r < 0)
1801 return r;
1802 if (r == 0)
1803 break;
1804
1805 /* Filter out arguments that are intended only for the
1806 * initrd */
1807 if (!in_initrd() && startswith(word, "rd."))
1808 continue;
1809
1810 if (value) {
1811 e = startswith(word, key);
1812 if (!e)
1813 continue;
1814
1815 r = free_and_strdup(&ret, e);
1816 if (r < 0)
1817 return r;
1818
1819 found = true;
1820 } else {
1821 if (streq(word, key))
1822 found = true;
1823 }
1824 }
1825
1826 if (value) {
1827 *value = ret;
1828 ret = NULL;
1829 }
1830
1831 return found;
1832
1833}
1834
bc9fd78c
LP
1835int container_get_leader(const char *machine, pid_t *pid) {
1836 _cleanup_free_ char *s = NULL, *class = NULL;
1837 const char *p;
1838 pid_t leader;
1839 int r;
1840
1841 assert(machine);
1842 assert(pid);
1843
b9a8d250
LP
1844 if (!machine_name_is_valid(machine))
1845 return -EINVAL;
1846
63c372cb 1847 p = strjoina("/run/systemd/machines/", machine);
bc9fd78c
LP
1848 r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
1849 if (r == -ENOENT)
1850 return -EHOSTDOWN;
1851 if (r < 0)
1852 return r;
1853 if (!s)
1854 return -EIO;
1855
1856 if (!streq_ptr(class, "container"))
1857 return -EIO;
1858
1859 r = parse_pid(s, &leader);
1860 if (r < 0)
1861 return r;
1862 if (leader <= 1)
1863 return -EIO;
1864
1865 *pid = leader;
1866 return 0;
1867}
1868
671c3419
RM
1869int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
1870 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
359a06aa 1871 int rfd = -1;
bc9fd78c
LP
1872
1873 assert(pid >= 0);
bc9fd78c 1874
878cd7e9
LP
1875 if (mntns_fd) {
1876 const char *mntns;
a4475f57 1877
878cd7e9
LP
1878 mntns = procfs_file_alloca(pid, "ns/mnt");
1879 mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1880 if (mntnsfd < 0)
1881 return -errno;
1882 }
bc9fd78c 1883
878cd7e9
LP
1884 if (pidns_fd) {
1885 const char *pidns;
1886
1887 pidns = procfs_file_alloca(pid, "ns/pid");
1888 pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1889 if (pidnsfd < 0)
1890 return -errno;
1891 }
1892
1893 if (netns_fd) {
1894 const char *netns;
1895
1896 netns = procfs_file_alloca(pid, "ns/net");
1897 netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1898 if (netnsfd < 0)
1899 return -errno;
1900 }
1901
671c3419
RM
1902 if (userns_fd) {
1903 const char *userns;
1904
1905 userns = procfs_file_alloca(pid, "ns/user");
1906 usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1907 if (usernsfd < 0 && errno != ENOENT)
1908 return -errno;
1909 }
1910
878cd7e9
LP
1911 if (root_fd) {
1912 const char *root;
1913
1914 root = procfs_file_alloca(pid, "root");
1915 rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1916 if (rfd < 0)
1917 return -errno;
1918 }
1919
1920 if (pidns_fd)
1921 *pidns_fd = pidnsfd;
bc9fd78c 1922
878cd7e9
LP
1923 if (mntns_fd)
1924 *mntns_fd = mntnsfd;
1925
1926 if (netns_fd)
1927 *netns_fd = netnsfd;
1928
671c3419
RM
1929 if (userns_fd)
1930 *userns_fd = usernsfd;
1931
878cd7e9
LP
1932 if (root_fd)
1933 *root_fd = rfd;
1934
671c3419 1935 pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
bc9fd78c
LP
1936
1937 return 0;
1938}
1939
671c3419
RM
1940int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
1941 if (userns_fd >= 0) {
1942 /* Can't setns to your own userns, since then you could
1943 * escalate from non-root to root in your own namespace, so
1944 * check if namespaces equal before attempting to enter. */
1945 _cleanup_free_ char *userns_fd_path = NULL;
1946 int r;
1947 if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
1948 return -ENOMEM;
1949
1950 r = files_same(userns_fd_path, "/proc/self/ns/user");
1951 if (r < 0)
1952 return r;
1953 if (r)
1954 userns_fd = -1;
1955 }
bc9fd78c 1956
878cd7e9
LP
1957 if (pidns_fd >= 0)
1958 if (setns(pidns_fd, CLONE_NEWPID) < 0)
1959 return -errno;
a4475f57 1960
878cd7e9
LP
1961 if (mntns_fd >= 0)
1962 if (setns(mntns_fd, CLONE_NEWNS) < 0)
1963 return -errno;
bc9fd78c 1964
878cd7e9
LP
1965 if (netns_fd >= 0)
1966 if (setns(netns_fd, CLONE_NEWNET) < 0)
1967 return -errno;
bc9fd78c 1968
671c3419
RM
1969 if (userns_fd >= 0)
1970 if (setns(userns_fd, CLONE_NEWUSER) < 0)
1971 return -errno;
1972
878cd7e9
LP
1973 if (root_fd >= 0) {
1974 if (fchdir(root_fd) < 0)
1975 return -errno;
1976
1977 if (chroot(".") < 0)
1978 return -errno;
1979 }
bc9fd78c 1980
b4da6d6b 1981 return reset_uid_gid();
bc9fd78c 1982}
bf108e55 1983
fdb9161c
LP
1984int fd_warn_permissions(const char *path, int fd) {
1985 struct stat st;
1986
1987 if (fstat(fd, &st) < 0)
1988 return -errno;
1989
1990 if (st.st_mode & 0111)
1991 log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path);
1992
1993 if (st.st_mode & 0002)
1994 log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path);
1995
1996 if (getpid() == 1 && (st.st_mode & 0044) != 0044)
1997 log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path);
1998
1999 return 0;
2000}
6afc95b7 2001
ac45f971 2002unsigned long personality_from_string(const char *p) {
6afc95b7
LP
2003
2004 /* Parse a personality specifier. We introduce our own
2005 * identifiers that indicate specific ABIs, rather than just
2006 * hints regarding the register size, since we want to keep
2007 * things open for multiple locally supported ABIs for the
2008 * same register size. We try to reuse the ABI identifiers
2009 * used by libseccomp. */
2010
2011#if defined(__x86_64__)
2012
2013 if (streq(p, "x86"))
2014 return PER_LINUX32;
2015
2016 if (streq(p, "x86-64"))
2017 return PER_LINUX;
2018
2019#elif defined(__i386__)
2020
2021 if (streq(p, "x86"))
2022 return PER_LINUX;
7517f51e
HB
2023
2024#elif defined(__s390x__)
2025
2026 if (streq(p, "s390"))
2027 return PER_LINUX32;
2028
2029 if (streq(p, "s390x"))
2030 return PER_LINUX;
2031
2032#elif defined(__s390__)
2033
2034 if (streq(p, "s390"))
2035 return PER_LINUX;
6afc95b7
LP
2036#endif
2037
050f7277 2038 return PERSONALITY_INVALID;
6afc95b7 2039}
ac45f971
LP
2040
2041const char* personality_to_string(unsigned long p) {
2042
2043#if defined(__x86_64__)
2044
2045 if (p == PER_LINUX32)
2046 return "x86";
2047
2048 if (p == PER_LINUX)
2049 return "x86-64";
2050
2051#elif defined(__i386__)
2052
2053 if (p == PER_LINUX)
2054 return "x86";
7517f51e
HB
2055
2056#elif defined(__s390x__)
2057
2058 if (p == PER_LINUX)
2059 return "s390x";
2060
2061 if (p == PER_LINUX32)
2062 return "s390";
2063
2064#elif defined(__s390__)
2065
2066 if (p == PER_LINUX)
2067 return "s390";
2068
ac45f971
LP
2069#endif
2070
2071 return NULL;
2072}
1c231f56
LP
2073
2074uint64_t physical_memory(void) {
2075 long mem;
2076
2077 /* We return this as uint64_t in case we are running as 32bit
2078 * process on a 64bit kernel with huge amounts of memory */
2079
2080 mem = sysconf(_SC_PHYS_PAGES);
2081 assert(mem > 0);
2082
2083 return (uint64_t) mem * (uint64_t) page_size();
2084}
6db615c1 2085
966bff26 2086int update_reboot_param_file(const char *param) {
c5220a94
MO
2087 int r = 0;
2088
2089 if (param) {
4c1fc3e4 2090 r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE);
c5220a94 2091 if (r < 0)
e53fc357 2092 return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m");
c5220a94 2093 } else
e53fc357 2094 (void) unlink(REBOOT_PARAM_FILE);
c5220a94 2095
e53fc357 2096 return 0;
c5220a94 2097}
6d313367 2098
5261ba90
TT
2099int is_symlink(const char *path) {
2100 struct stat info;
2101
2102 if (lstat(path, &info) < 0)
2103 return -errno;
2104
be57e297
LP
2105 return !!S_ISLNK(info.st_mode);
2106}
5261ba90 2107
be57e297
LP
2108int is_dir(const char* path, bool follow) {
2109 struct stat st;
d1bddcec 2110 int r;
be57e297 2111
d1bddcec
LP
2112 if (follow)
2113 r = stat(path, &st);
2114 else
2115 r = lstat(path, &st);
2116 if (r < 0)
2117 return -errno;
be57e297
LP
2118
2119 return !!S_ISDIR(st.st_mode);
a0627f82 2120}
7629889c 2121
ce5b3ad4
SJ
2122int is_device_node(const char *path) {
2123 struct stat info;
2124
2125 if (lstat(path, &info) < 0)
2126 return -errno;
2127
2128 return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
2129}
2130
10f9c755 2131ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) {
df241a67 2132 char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
10f9c755
LP
2133 _cleanup_close_ int fd = -1;
2134 ssize_t l;
2135
2136 /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */
2137
df241a67 2138 fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
10f9c755
LP
2139 if (fd < 0)
2140 return -errno;
2141
df241a67
LP
2142 xsprintf(fn, "/proc/self/fd/%i", fd);
2143
2144 l = getxattr(fn, attribute, value, size);
10f9c755
LP
2145 if (l < 0)
2146 return -errno;
2147
2148 return l;
2149}
2150
2151static int parse_crtime(le64_t le, usec_t *usec) {
4a4d89b6 2152 uint64_t u;
10f9c755
LP
2153
2154 assert(usec);
2155
2156 u = le64toh(le);
2157 if (u == 0 || u == (uint64_t) -1)
2158 return -EIO;
2159
2160 *usec = (usec_t) u;
2161 return 0;
2162}
2163
2164int fd_getcrtime(int fd, usec_t *usec) {
4a4d89b6
LP
2165 le64_t le;
2166 ssize_t n;
2167
2168 assert(fd >= 0);
2169 assert(usec);
2170
2171 /* Until Linux gets a real concept of birthtime/creation time,
2172 * let's fake one with xattrs */
2173
2174 n = fgetxattr(fd, "user.crtime_usec", &le, sizeof(le));
2175 if (n < 0)
2176 return -errno;
2177 if (n != sizeof(le))
2178 return -EIO;
2179
10f9c755
LP
2180 return parse_crtime(le, usec);
2181}
2182
2183int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags) {
2184 le64_t le;
2185 ssize_t n;
2186
2187 n = fgetxattrat_fake(dirfd, name, "user.crtime_usec", &le, sizeof(le), flags);
2188 if (n < 0)
2189 return -errno;
2190 if (n != sizeof(le))
4a4d89b6
LP
2191 return -EIO;
2192
10f9c755 2193 return parse_crtime(le, usec);
4a4d89b6
LP
2194}
2195
2196int path_getcrtime(const char *p, usec_t *usec) {
4a4d89b6
LP
2197 le64_t le;
2198 ssize_t n;
2199
2200 assert(p);
2201 assert(usec);
2202
2203 n = getxattr(p, "user.crtime_usec", &le, sizeof(le));
2204 if (n < 0)
2205 return -errno;
2206 if (n != sizeof(le))
2207 return -EIO;
2208
10f9c755 2209 return parse_crtime(le, usec);
4a4d89b6
LP
2210}
2211
2212int fd_setcrtime(int fd, usec_t usec) {
2213 le64_t le;
2214
2215 assert(fd >= 0);
2216
d61b600d
LP
2217 if (usec <= 0)
2218 usec = now(CLOCK_REALTIME);
2219
4a4d89b6 2220 le = htole64((uint64_t) usec);
2c39ea52 2221 if (fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), 0) < 0)
4a4d89b6
LP
2222 return -errno;
2223
2224 return 0;
2225}
a354329f 2226
1ed8f8c1 2227int chattr_fd(int fd, unsigned value, unsigned mask) {
45030287 2228 unsigned old_attr, new_attr;
03091baa 2229 struct stat st;
11689d2a
LP
2230
2231 assert(fd >= 0);
2232
03091baa
LP
2233 if (fstat(fd, &st) < 0)
2234 return -errno;
2235
2236 /* Explicitly check whether this is a regular file or
2237 * directory. If it is anything else (such as a device node or
2238 * fifo), then the ioctl will not hit the file systems but
2239 * possibly drivers, where the ioctl might have different
2240 * effects. Notably, DRM is using the same ioctl() number. */
2241
2242 if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
2243 return -ENOTTY;
2244
45030287
LP
2245 if (mask == 0)
2246 return 0;
2247
11689d2a
LP
2248 if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0)
2249 return -errno;
2250
1ed8f8c1 2251 new_attr = (old_attr & ~mask) | (value & mask);
11689d2a
LP
2252 if (new_attr == old_attr)
2253 return 0;
2254
2255 if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0)
2256 return -errno;
2257
1ed8f8c1 2258 return 1;
11689d2a
LP
2259}
2260
1ed8f8c1 2261int chattr_path(const char *p, unsigned value, unsigned mask) {
11689d2a
LP
2262 _cleanup_close_ int fd = -1;
2263
45030287
LP
2264 assert(p);
2265
2266 if (mask == 0)
2267 return 0;
2268
01b72568 2269 fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
11689d2a
LP
2270 if (fd < 0)
2271 return -errno;
2272
1ed8f8c1 2273 return chattr_fd(fd, value, mask);
5b9fbd35
GB
2274}
2275
01b72568 2276int read_attr_fd(int fd, unsigned *ret) {
03091baa
LP
2277 struct stat st;
2278
01b72568
LP
2279 assert(fd >= 0);
2280
03091baa
LP
2281 if (fstat(fd, &st) < 0)
2282 return -errno;
2283
2284 if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
2285 return -ENOTTY;
2286
01b72568
LP
2287 if (ioctl(fd, FS_IOC_GETFLAGS, ret) < 0)
2288 return -errno;
2289
2290 return 0;
2291}
2292
2293int read_attr_path(const char *p, unsigned *ret) {
2294 _cleanup_close_ int fd = -1;
2295
2296 assert(p);
2297 assert(ret);
2298
2299 fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2300 if (fd < 0)
2301 return -errno;
2302
2303 return read_attr_fd(fd, ret);
2304}
30535c16 2305
3d7415f4
LP
2306int syslog_parse_priority(const char **p, int *priority, bool with_facility) {
2307 int a = 0, b = 0, c = 0;
2308 int k;
2309
2310 assert(p);
2311 assert(*p);
2312 assert(priority);
2313
2314 if ((*p)[0] != '<')
2315 return 0;
2316
2317 if (!strchr(*p, '>'))
2318 return 0;
2319
2320 if ((*p)[2] == '>') {
2321 c = undecchar((*p)[1]);
2322 k = 3;
2323 } else if ((*p)[3] == '>') {
2324 b = undecchar((*p)[1]);
2325 c = undecchar((*p)[2]);
2326 k = 4;
2327 } else if ((*p)[4] == '>') {
2328 a = undecchar((*p)[1]);
2329 b = undecchar((*p)[2]);
2330 c = undecchar((*p)[3]);
2331 k = 5;
2332 } else
2333 return 0;
2334
2335 if (a < 0 || b < 0 || c < 0 ||
2336 (!with_facility && (a || b || c > 7)))
2337 return 0;
2338
2339 if (with_facility)
2340 *priority = a*100 + b*10 + c;
2341 else
2342 *priority = (*priority & LOG_FACMASK) | c;
2343
2344 *p += k;
2345 return 1;
2346}
9cad100e
BB
2347
2348ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) {
2349 size_t i;
2350
2351 if (!key)
2352 return -1;
2353
2354 for (i = 0; i < len; ++i)
2355 if (streq_ptr(table[i], key))
8c721f2b 2356 return (ssize_t) i;
9cad100e
BB
2357
2358 return -1;
2359}
1c8da044 2360
f85ef957
AC
2361int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
2362 struct stat buf;
2363 int ret;
2364
2365 ret = renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE);
2366 if (ret >= 0)
2367 return 0;
2368
715d7599
RM
2369 /* renameat2() exists since Linux 3.15, btrfs added support for it later.
2370 * If it is not implemented, fallback to another method. */
2371 if (!IN_SET(errno, EINVAL, ENOSYS))
f85ef957
AC
2372 return -errno;
2373
2374 /* The link()/unlink() fallback does not work on directories. But
2375 * renameat() without RENAME_NOREPLACE gives the same semantics on
2376 * directories, except when newpath is an *empty* directory. This is
2377 * good enough. */
2378 ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW);
2379 if (ret >= 0 && S_ISDIR(buf.st_mode)) {
2380 ret = renameat(olddirfd, oldpath, newdirfd, newpath);
2381 return ret >= 0 ? 0 : -errno;
2382 }
2383
2384 /* If it is not a directory, use the link()/unlink() fallback. */
2385 ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0);
2386 if (ret < 0)
2387 return -errno;
2388
2389 ret = unlinkat(olddirfd, oldpath, 0);
2390 if (ret < 0) {
2391 /* backup errno before the following unlinkat() alters it */
2392 ret = errno;
2393 (void) unlinkat(newdirfd, newpath, 0);
2394 errno = ret;
2395 return -errno;
2396 }
2397
2398 return 0;
2399}
019c7fba 2400
7b9c9ab8
WC
2401int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink) {
2402 char *v;
2403 size_t l;
2404 ssize_t n;
2405
2406 assert(path);
2407 assert(name);
2408 assert(value);
2409
2410 for (l = 100; ; l = (size_t) n + 1) {
2411 v = new0(char, l);
2412 if (!v)
2413 return -ENOMEM;
2414
2415 if (allow_symlink)
2416 n = lgetxattr(path, name, v, l);
2417 else
2418 n = getxattr(path, name, v, l);
2419
2420 if (n >= 0 && (size_t) n < l) {
2421 *value = v;
2422 return n;
2423 }
2424
2425 free(v);
2426
2427 if (n < 0 && errno != ERANGE)
2428 return -errno;
2429
2430 if (allow_symlink)
2431 n = lgetxattr(path, name, NULL, 0);
2432 else
2433 n = getxattr(path, name, NULL, 0);
2434 if (n < 0)
2435 return -errno;
2436 }
2437}
2438
2439int fgetxattr_malloc(int fd, const char *name, char **value) {
2440 char *v;
2441 size_t l;
2442 ssize_t n;
2443
2444 assert(fd >= 0);
2445 assert(name);
2446 assert(value);
2447
2448 for (l = 100; ; l = (size_t) n + 1) {
2449 v = new0(char, l);
2450 if (!v)
2451 return -ENOMEM;
2452
2453 n = fgetxattr(fd, name, v, l);
2454
2455 if (n >= 0 && (size_t) n < l) {
2456 *value = v;
2457 return n;
2458 }
2459
2460 free(v);
2461
2462 if (n < 0 && errno != ERANGE)
2463 return -errno;
2464
2465 n = fgetxattr(fd, name, NULL, 0);
2466 if (n < 0)
2467 return -errno;
2468 }
2469}
d9603714 2470
3f6fd1ba
LP
2471int version(void) {
2472 puts(PACKAGE_STRING "\n"
2473 SYSTEMD_FEATURES);
2474 return 0;
2475}
8dd4c05b
LP
2476
2477bool fdname_is_valid(const char *s) {
2478 const char *p;
2479
0a3bb96e 2480 /* Validates a name for $LISTEN_FDNAMES. We basically allow
8dd4c05b
LP
2481 * everything ASCII that's not a control character. Also, as
2482 * special exception the ":" character is not allowed, as we
0a3bb96e 2483 * use that as field separator in $LISTEN_FDNAMES.
8dd4c05b 2484 *
0a3bb96e
LP
2485 * Note that the empty string is explicitly allowed
2486 * here. However, we limit the length of the names to 255
2487 * characters. */
8dd4c05b
LP
2488
2489 if (!s)
2490 return false;
2491
2492 for (p = s; *p; p++) {
2493 if (*p < ' ')
2494 return false;
2495 if (*p >= 127)
2496 return false;
2497 if (*p == ':')
2498 return false;
2499 }
2500
2501 return p - s < 256;
2502}
257b0719
EV
2503
2504bool oom_score_adjust_is_valid(int oa) {
2505 return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX;
2506}