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