]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/util.c
util-lib: move a number of fs operations into fs-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 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>
f6c2284a
LP
56#include <syslog.h>
57#include <unistd.h>
eef46c37
LP
58
59/* When we include libgen.h because we need dirname() we immediately
f6c2284a
LP
60 * undefine basename() since libgen.h defines it as a macro to the
61 * POSIX version which is really broken. We prefer GNU basename(). */
eef46c37 62#include <libgen.h>
2b6bf07d 63#undef basename
60918275 64
9bf3b535
LP
65#ifdef HAVE_SYS_AUXV_H
66#include <sys/auxv.h>
67#endif
68
f6c2284a
LP
69/* We include linux/fs.h as last of the system headers, as it
70 * otherwise conflicts with sys/mount.h. Yay, Linux is great! */
71#include <linux/fs.h>
72
3f6fd1ba 73#include "build.h"
f6c2284a
LP
74#include "def.h"
75#include "device-nodes.h"
76#include "env-util.h"
4f5dd394 77#include "escape.h"
f6c2284a 78#include "exit-status.h"
3ffd4af2 79#include "fd-util.h"
f6c2284a
LP
80#include "fileio.h"
81#include "formats-util.h"
82#include "gunicode.h"
83#include "hashmap.h"
84#include "hostname-util.h"
1dccbe19 85#include "ioprio.h"
a9f5d454 86#include "log.h"
f6c2284a
LP
87#include "macro.h"
88#include "missing.h"
c38dfac9 89#include "mkdir.h"
e4e73a63 90#include "hexdecoct.h"
6bedfcbb 91#include "parse-util.h"
9eb977db 92#include "path-util.h"
0b452006 93#include "process-util.h"
3df3e884 94#include "random-util.h"
24882e06 95#include "signal-util.h"
f6c2284a 96#include "sparse-endian.h"
07630cea 97#include "string-util.h"
f6c2284a
LP
98#include "strv.h"
99#include "terminal-util.h"
b1d4f8e1 100#include "user-util.h"
f6c2284a 101#include "utf8.h"
4f5dd394 102#include "util.h"
3ffd4af2 103#include "virt.h"
a0956174 104#include "dirent-util.h"
56cf987f 105
012d7b42
ZJS
106/* Put this test here for a lack of better place */
107assert_cc(EAGAIN == EWOULDBLOCK);
108
9a0e6896
LP
109int saved_argc = 0;
110char **saved_argv = NULL;
9086e840 111
37f85e66 112size_t page_size(void) {
ec202eae 113 static thread_local size_t pgsz = 0;
37f85e66 114 long r;
115
87d2c1ff 116 if (_likely_(pgsz > 0))
37f85e66 117 return pgsz;
118
e67f47e5
LP
119 r = sysconf(_SC_PAGESIZE);
120 assert(r > 0);
37f85e66 121
122 pgsz = (size_t) r;
37f85e66 123 return pgsz;
124}
125
42856c10 126bool fstype_is_network(const char *fstype) {
a05f97b3 127 static const char table[] =
ba89821c 128 "afs\0"
a05f97b3
LP
129 "cifs\0"
130 "smbfs\0"
da92ca5e 131 "sshfs\0"
a05f97b3 132 "ncpfs\0"
dac70dc7 133 "ncp\0"
a05f97b3
LP
134 "nfs\0"
135 "nfs4\0"
136 "gfs\0"
67608cad
LP
137 "gfs2\0"
138 "glusterfs\0";
139
140 const char *x;
141
142 x = startswith(fstype, "fuse.");
143 if (x)
144 fstype = x;
42856c10 145
a05f97b3 146 return nulstr_contains(table, fstype);
42856c10
LP
147}
148
01f78473 149int dir_is_empty(const char *path) {
a05f97b3 150 _cleanup_closedir_ DIR *d;
ac7edd91 151 struct dirent *de;
01f78473 152
a05f97b3
LP
153 d = opendir(path);
154 if (!d)
01f78473
LP
155 return -errno;
156
ac7edd91
LP
157 FOREACH_DIRENT(de, d, return -errno)
158 return 0;
01f78473 159
ac7edd91 160 return 1;
01f78473
LP
161}
162
5b6319dc
LP
163void rename_process(const char name[8]) {
164 assert(name);
165
5d6b1584
LP
166 /* This is a like a poor man's setproctitle(). It changes the
167 * comm field, argv[0], and also the glibc's internally used
168 * name of the process. For the first one a limit of 16 chars
169 * applies, to the second one usually one of 10 (i.e. length
170 * of "/sbin/init"), to the third one one of 7 (i.e. length of
171 * "systemd"). If you pass a longer string it will be
172 * truncated */
5b6319dc 173
5d6b1584 174 prctl(PR_SET_NAME, name);
5b6319dc
LP
175
176 if (program_invocation_name)
177 strncpy(program_invocation_name, name, strlen(program_invocation_name));
9a0e6896
LP
178
179 if (saved_argc > 0) {
180 int i;
181
182 if (saved_argv[0])
183 strncpy(saved_argv[0], name, strlen(saved_argv[0]));
184
185 for (i = 1; i < saved_argc; i++) {
186 if (!saved_argv[i])
187 break;
188
29804cc1 189 memzero(saved_argv[i], strlen(saved_argv[i]));
9a0e6896
LP
190 }
191 }
5b6319dc
LP
192}
193
d1678248 194bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
943aad8c 195 assert(s);
d1678248
ILG
196 assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
197
198 return F_TYPE_EQUAL(s->f_type, magic_value);
199}
200
201int fd_check_fstype(int fd, statfs_f_type_t magic_value) {
202 struct statfs s;
203
204 if (fstatfs(fd, &s) < 0)
205 return -errno;
73020ab2 206
d1678248
ILG
207 return is_fs_type(&s, magic_value);
208}
209
210int path_check_fstype(const char *path, statfs_f_type_t magic_value) {
211 _cleanup_close_ int fd = -1;
212
213 fd = open(path, O_RDONLY);
214 if (fd < 0)
215 return -errno;
216
217 return fd_check_fstype(fd, magic_value);
218}
219
220bool is_temporary_fs(const struct statfs *s) {
221 return is_fs_type(s, TMPFS_MAGIC) ||
222 is_fs_type(s, RAMFS_MAGIC);
943aad8c
ZJS
223}
224
c6878637 225int fd_is_temporary_fs(int fd) {
979ef53a
DR
226 struct statfs s;
227
228 if (fstatfs(fd, &s) < 0)
229 return -errno;
230
231 return is_temporary_fs(&s);
232}
233
9d9951a4
HH
234int files_same(const char *filea, const char *fileb) {
235 struct stat a, b;
b4f10a5e 236
9d9951a4 237 if (stat(filea, &a) < 0)
b4f10a5e
LP
238 return -errno;
239
9d9951a4 240 if (stat(fileb, &b) < 0)
b4f10a5e
LP
241 return -errno;
242
9d9951a4
HH
243 return a.st_dev == b.st_dev &&
244 a.st_ino == b.st_ino;
245}
246
247int running_in_chroot(void) {
248 int ret;
249
250 ret = files_same("/proc/1/root", "/");
251 if (ret < 0)
252 return ret;
253
254 return ret == 0;
b4f10a5e
LP
255}
256
919ce0b7 257noreturn void freeze(void) {
720ce21d
LP
258
259 /* Make sure nobody waits for us on a socket anymore */
260 close_all_fds(NULL, 0);
261
c29597a1
LP
262 sync();
263
3c14d26c
LP
264 for (;;)
265 pause();
266}
267
00dc5d76
LP
268bool null_or_empty(struct stat *st) {
269 assert(st);
270
271 if (S_ISREG(st->st_mode) && st->st_size <= 0)
272 return true;
273
c8f26f42 274 if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
00dc5d76
LP
275 return true;
276
277 return false;
278}
279
83096483
LP
280int null_or_empty_path(const char *fn) {
281 struct stat st;
282
283 assert(fn);
284
285 if (stat(fn, &st) < 0)
286 return -errno;
287
288 return null_or_empty(&st);
289}
290
ed88bcfb
ZJS
291int null_or_empty_fd(int fd) {
292 struct stat st;
293
294 assert(fd >= 0);
295
296 if (fstat(fd, &st) < 0)
297 return -errno;
298
299 return null_or_empty(&st);
300}
301
e801700e 302static int do_execute(char **directories, usec_t timeout, char *argv[]) {
49681057 303 _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
e801700e
ZJS
304 _cleanup_set_free_free_ Set *seen = NULL;
305 char **directory;
83cc030f 306
49681057
ZJS
307 /* We fork this all off from a child process so that we can
308 * somewhat cleanly make use of SIGALRM to set a time limit */
83cc030f 309
ce30c8dc
LP
310 (void) reset_all_signal_handlers();
311 (void) reset_signal_mask();
83cc030f 312
49681057 313 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
83cc030f 314
49681057
ZJS
315 pids = hashmap_new(NULL);
316 if (!pids)
317 return log_oom();
83cc030f 318
e801700e
ZJS
319 seen = set_new(&string_hash_ops);
320 if (!seen)
321 return log_oom();
83cc030f 322
e801700e
ZJS
323 STRV_FOREACH(directory, directories) {
324 _cleanup_closedir_ DIR *d;
325 struct dirent *de;
83cc030f 326
e801700e
ZJS
327 d = opendir(*directory);
328 if (!d) {
329 if (errno == ENOENT)
330 continue;
83cc030f 331
e801700e
ZJS
332 return log_error_errno(errno, "Failed to open directory %s: %m", *directory);
333 }
83cc030f 334
e801700e
ZJS
335 FOREACH_DIRENT(de, d, break) {
336 _cleanup_free_ char *path = NULL;
337 pid_t pid;
338 int r;
339
340 if (!dirent_is_file(de))
341 continue;
83cc030f 342
e801700e
ZJS
343 if (set_contains(seen, de->d_name)) {
344 log_debug("%1$s/%2$s skipped (%2$s was already seen).", *directory, de->d_name);
345 continue;
346 }
347
348 r = set_put_strdup(seen, de->d_name);
349 if (r < 0)
350 return log_oom();
351
352 path = strjoin(*directory, "/", de->d_name, NULL);
353 if (!path)
354 return log_oom();
355
356 if (null_or_empty_path(path)) {
357 log_debug("%s is empty (a mask).", path);
358 continue;
7034e9db 359 }
83cc030f 360
e801700e
ZJS
361 pid = fork();
362 if (pid < 0) {
363 log_error_errno(errno, "Failed to fork: %m");
364 continue;
365 } else if (pid == 0) {
366 char *_argv[2];
83cc030f 367
e801700e 368 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
83cc030f 369
e801700e
ZJS
370 if (!argv) {
371 _argv[0] = path;
372 _argv[1] = NULL;
373 argv = _argv;
374 } else
375 argv[0] = path;
376
377 execv(path, argv);
378 return log_error_errno(errno, "Failed to execute %s: %m", path);
379 }
380
381 log_debug("Spawned %s as " PID_FMT ".", path, pid);
83cc030f 382
e801700e
ZJS
383 r = hashmap_put(pids, UINT_TO_PTR(pid), path);
384 if (r < 0)
385 return log_oom();
386 path = NULL;
387 }
49681057 388 }
83cc030f 389
49681057
ZJS
390 /* Abort execution of this process after the timout. We simply
391 * rely on SIGALRM as default action terminating the process,
392 * and turn on alarm(). */
83cc030f 393
49681057
ZJS
394 if (timeout != USEC_INFINITY)
395 alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
83cc030f 396
49681057
ZJS
397 while (!hashmap_isempty(pids)) {
398 _cleanup_free_ char *path = NULL;
399 pid_t pid;
aa62a893 400
49681057
ZJS
401 pid = PTR_TO_UINT(hashmap_first_key(pids));
402 assert(pid > 0);
83cc030f 403
49681057
ZJS
404 path = hashmap_remove(pids, UINT_TO_PTR(pid));
405 assert(path);
aa62a893 406
49681057
ZJS
407 wait_for_terminate_and_warn(path, pid, true);
408 }
aa62a893 409
49681057
ZJS
410 return 0;
411}
aa62a893 412
e801700e 413void execute_directories(const char* const* directories, usec_t timeout, char *argv[]) {
49681057
ZJS
414 pid_t executor_pid;
415 int r;
e801700e
ZJS
416 char *name;
417 char **dirs = (char**) directories;
418
419 assert(!strv_isempty(dirs));
83cc030f 420
e801700e
ZJS
421 name = basename(dirs[0]);
422 assert(!isempty(name));
aa62a893 423
e801700e
ZJS
424 /* Executes all binaries in the directories in parallel and waits
425 * for them to finish. Optionally a timeout is applied. If a file
426 * with the same name exists in more than one directory, the
427 * earliest one wins. */
83cc030f 428
49681057
ZJS
429 executor_pid = fork();
430 if (executor_pid < 0) {
431 log_error_errno(errno, "Failed to fork: %m");
432 return;
433
434 } else if (executor_pid == 0) {
e801700e 435 r = do_execute(dirs, timeout, argv);
49681057 436 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
aa62a893 437 }
83cc030f 438
e801700e 439 wait_for_terminate_and_warn(name, executor_pid, true);
83cc030f
LP
440}
441
a88c8750
TG
442bool plymouth_running(void) {
443 return access("/run/plymouth/pid", F_OK) >= 0;
444}
445
4d6d6518
LP
446bool display_is_local(const char *display) {
447 assert(display);
448
449 return
450 display[0] == ':' &&
451 display[1] >= '0' &&
452 display[1] <= '9';
453}
454
455int socket_from_display(const char *display, char **path) {
456 size_t k;
457 char *f, *c;
458
459 assert(display);
460 assert(path);
461
462 if (!display_is_local(display))
463 return -EINVAL;
464
465 k = strspn(display+1, "0123456789");
466
f8294e41 467 f = new(char, strlen("/tmp/.X11-unix/X") + k + 1);
4d6d6518
LP
468 if (!f)
469 return -ENOMEM;
470
471 c = stpcpy(f, "/tmp/.X11-unix/X");
472 memcpy(c, display+1, k);
473 c[k] = 0;
474
475 *path = f;
476
477 return 0;
478}
479
8092a428 480int glob_exists(const char *path) {
7fd1b19b 481 _cleanup_globfree_ glob_t g = {};
8d98da3f 482 int k;
8092a428
LP
483
484 assert(path);
485
8092a428
LP
486 errno = 0;
487 k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
488
489 if (k == GLOB_NOMATCH)
8d98da3f 490 return 0;
8092a428 491 else if (k == GLOB_NOSPACE)
8d98da3f 492 return -ENOMEM;
8092a428 493 else if (k == 0)
8d98da3f 494 return !strv_isempty(g.gl_pathv);
8092a428 495 else
8d98da3f
ZJS
496 return errno ? -errno : -EIO;
497}
8092a428 498
8d98da3f
ZJS
499int glob_extend(char ***strv, const char *path) {
500 _cleanup_globfree_ glob_t g = {};
501 int k;
502 char **p;
503
504 errno = 0;
a8ccacf5 505 k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
8d98da3f
ZJS
506
507 if (k == GLOB_NOMATCH)
508 return -ENOENT;
509 else if (k == GLOB_NOSPACE)
510 return -ENOMEM;
511 else if (k != 0 || strv_isempty(g.gl_pathv))
512 return errno ? -errno : -EIO;
513
514 STRV_FOREACH(p, g.gl_pathv) {
515 k = strv_extend(strv, *p);
516 if (k < 0)
517 break;
518 }
519
520 return k;
8092a428
LP
521}
522
b636465b 523bool is_main_thread(void) {
ec202eae 524 static thread_local int cached = 0;
b636465b
LP
525
526 if (_unlikely_(cached == 0))
527 cached = getpid() == gettid() ? 1 : -1;
528
529 return cached > 0;
530}
531
94959f0f
LP
532int block_get_whole_disk(dev_t d, dev_t *ret) {
533 char *p, *s;
534 int r;
535 unsigned n, m;
536
537 assert(ret);
538
539 /* If it has a queue this is good enough for us */
540 if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0)
541 return -ENOMEM;
542
543 r = access(p, F_OK);
544 free(p);
545
546 if (r >= 0) {
547 *ret = d;
548 return 0;
549 }
550
551 /* If it is a partition find the originating device */
552 if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0)
553 return -ENOMEM;
554
555 r = access(p, F_OK);
556 free(p);
557
558 if (r < 0)
559 return -ENOENT;
560
561 /* Get parent dev_t */
562 if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0)
563 return -ENOMEM;
564
565 r = read_one_line_file(p, &s);
566 free(p);
567
568 if (r < 0)
569 return r;
570
571 r = sscanf(s, "%u:%u", &m, &n);
572 free(s);
573
574 if (r != 2)
575 return -EINVAL;
576
577 /* Only return this if it is really good enough for us. */
578 if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0)
579 return -ENOMEM;
580
581 r = access(p, F_OK);
582 free(p);
583
584 if (r >= 0) {
585 *ret = makedev(m, n);
586 return 0;
587 }
588
589 return -ENOENT;
590}
591
f41607a6
LP
592static const char *const ioprio_class_table[] = {
593 [IOPRIO_CLASS_NONE] = "none",
594 [IOPRIO_CLASS_RT] = "realtime",
595 [IOPRIO_CLASS_BE] = "best-effort",
596 [IOPRIO_CLASS_IDLE] = "idle"
597};
598
f8b69d1d 599DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX);
f41607a6
LP
600
601static const char *const sigchld_code_table[] = {
602 [CLD_EXITED] = "exited",
603 [CLD_KILLED] = "killed",
604 [CLD_DUMPED] = "dumped",
605 [CLD_TRAPPED] = "trapped",
606 [CLD_STOPPED] = "stopped",
607 [CLD_CONTINUED] = "continued",
608};
609
610DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
611
612static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = {
613 [LOG_FAC(LOG_KERN)] = "kern",
614 [LOG_FAC(LOG_USER)] = "user",
615 [LOG_FAC(LOG_MAIL)] = "mail",
616 [LOG_FAC(LOG_DAEMON)] = "daemon",
617 [LOG_FAC(LOG_AUTH)] = "auth",
618 [LOG_FAC(LOG_SYSLOG)] = "syslog",
619 [LOG_FAC(LOG_LPR)] = "lpr",
620 [LOG_FAC(LOG_NEWS)] = "news",
621 [LOG_FAC(LOG_UUCP)] = "uucp",
622 [LOG_FAC(LOG_CRON)] = "cron",
623 [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
624 [LOG_FAC(LOG_FTP)] = "ftp",
625 [LOG_FAC(LOG_LOCAL0)] = "local0",
626 [LOG_FAC(LOG_LOCAL1)] = "local1",
627 [LOG_FAC(LOG_LOCAL2)] = "local2",
628 [LOG_FAC(LOG_LOCAL3)] = "local3",
629 [LOG_FAC(LOG_LOCAL4)] = "local4",
630 [LOG_FAC(LOG_LOCAL5)] = "local5",
631 [LOG_FAC(LOG_LOCAL6)] = "local6",
632 [LOG_FAC(LOG_LOCAL7)] = "local7"
633};
634
f8b69d1d 635DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0));
f41607a6 636
adb8ec96
EV
637bool log_facility_unshifted_is_valid(int facility) {
638 return facility >= 0 && facility <= LOG_FAC(~0);
639}
640
f41607a6
LP
641static const char *const log_level_table[] = {
642 [LOG_EMERG] = "emerg",
643 [LOG_ALERT] = "alert",
644 [LOG_CRIT] = "crit",
645 [LOG_ERR] = "err",
646 [LOG_WARNING] = "warning",
647 [LOG_NOTICE] = "notice",
648 [LOG_INFO] = "info",
649 [LOG_DEBUG] = "debug"
650};
651
f8b69d1d 652DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG);
f41607a6 653
adb8ec96
EV
654bool log_level_is_valid(int level) {
655 return level >= 0 && level <= LOG_DEBUG;
656}
657
f41607a6
LP
658static const char* const sched_policy_table[] = {
659 [SCHED_OTHER] = "other",
660 [SCHED_BATCH] = "batch",
661 [SCHED_IDLE] = "idle",
662 [SCHED_FIFO] = "fifo",
663 [SCHED_RR] = "rr"
664};
665
f8b69d1d 666DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
f41607a6 667
65457142
FC
668bool kexec_loaded(void) {
669 bool loaded = false;
670 char *s;
671
672 if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) {
673 if (s[0] == '1')
674 loaded = true;
675 free(s);
676 }
677 return loaded;
678}
fb9de93d 679
87d2c1ff
LP
680int prot_from_flags(int flags) {
681
682 switch (flags & O_ACCMODE) {
683
684 case O_RDONLY:
685 return PROT_READ;
686
687 case O_WRONLY:
688 return PROT_WRITE;
689
690 case O_RDWR:
691 return PROT_READ|PROT_WRITE;
692
693 default:
694 return -EINVAL;
695 }
7c99e0c1 696}
689b9a22 697
55d7bfc1
LP
698void* memdup(const void *p, size_t l) {
699 void *r;
700
701 assert(p);
702
703 r = malloc(l);
704 if (!r)
705 return NULL;
706
707 memcpy(r, p, l);
708 return r;
709}
bb99a35a 710
9bdc770c 711int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
6bb92a16 712 bool stdout_is_tty, stderr_is_tty;
8a7c93d8
LP
713 pid_t parent_pid, agent_pid;
714 sigset_t ss, saved_ss;
6bb92a16
LP
715 unsigned n, i;
716 va_list ap;
717 char **l;
718
719 assert(pid);
720 assert(path);
721
6bb92a16
LP
722 /* Spawns a temporary TTY agent, making sure it goes away when
723 * we go away */
724
8a7c93d8
LP
725 parent_pid = getpid();
726
727 /* First we temporarily block all signals, so that the new
728 * child has them blocked initially. This way, we can be sure
729 * that SIGTERMs are not lost we might send to the agent. */
730 assert_se(sigfillset(&ss) >= 0);
731 assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0);
732
6bb92a16 733 agent_pid = fork();
8a7c93d8
LP
734 if (agent_pid < 0) {
735 assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
6bb92a16 736 return -errno;
8a7c93d8 737 }
6bb92a16
LP
738
739 if (agent_pid != 0) {
8a7c93d8 740 assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
6bb92a16
LP
741 *pid = agent_pid;
742 return 0;
743 }
744
745 /* In the child:
746 *
747 * Make sure the agent goes away when the parent dies */
748 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
749 _exit(EXIT_FAILURE);
750
8a7c93d8
LP
751 /* Make sure we actually can kill the agent, if we need to, in
752 * case somebody invoked us from a shell script that trapped
753 * SIGTERM or so... */
ce30c8dc
LP
754 (void) reset_all_signal_handlers();
755 (void) reset_signal_mask();
8a7c93d8 756
6bb92a16 757 /* Check whether our parent died before we were able
8a7c93d8 758 * to set the death signal and unblock the signals */
6bb92a16
LP
759 if (getppid() != parent_pid)
760 _exit(EXIT_SUCCESS);
761
762 /* Don't leak fds to the agent */
9bdc770c 763 close_all_fds(except, n_except);
6bb92a16
LP
764
765 stdout_is_tty = isatty(STDOUT_FILENO);
766 stderr_is_tty = isatty(STDERR_FILENO);
767
768 if (!stdout_is_tty || !stderr_is_tty) {
8a7c93d8
LP
769 int fd;
770
6bb92a16
LP
771 /* Detach from stdout/stderr. and reopen
772 * /dev/tty for them. This is important to
773 * ensure that when systemctl is started via
774 * popen() or a similar call that expects to
775 * read EOF we actually do generate EOF and
776 * not delay this indefinitely by because we
777 * keep an unused copy of stdin around. */
778 fd = open("/dev/tty", O_WRONLY);
779 if (fd < 0) {
56f64d95 780 log_error_errno(errno, "Failed to open /dev/tty: %m");
6bb92a16
LP
781 _exit(EXIT_FAILURE);
782 }
783
784 if (!stdout_is_tty)
785 dup2(fd, STDOUT_FILENO);
786
787 if (!stderr_is_tty)
788 dup2(fd, STDERR_FILENO);
789
790 if (fd > 2)
791 close(fd);
792 }
793
794 /* Count arguments */
795 va_start(ap, path);
796 for (n = 0; va_arg(ap, char*); n++)
797 ;
798 va_end(ap);
799
800 /* Allocate strv */
801 l = alloca(sizeof(char *) * (n + 1));
802
803 /* Fill in arguments */
804 va_start(ap, path);
805 for (i = 0; i <= n; i++)
806 l[i] = va_arg(ap, char*);
807 va_end(ap);
808
809 execv(path, l);
810 _exit(EXIT_FAILURE);
811}
68faf98c 812
3d7415f4
LP
813bool http_etag_is_valid(const char *etag) {
814 if (isempty(etag))
815 return false;
816
817 if (!endswith(etag, "\""))
818 return false;
819
820 if (!startswith(etag, "\"") && !startswith(etag, "W/\""))
821 return false;
822
823 return true;
824}
825
a2e03378
LP
826bool http_url_is_valid(const char *url) {
827 const char *p;
49dbfa7b 828
a2e03378
LP
829 if (isempty(url))
830 return false;
49dbfa7b 831
a2e03378
LP
832 p = startswith(url, "http://");
833 if (!p)
834 p = startswith(url, "https://");
835 if (!p)
836 return false;
49dbfa7b 837
a2e03378
LP
838 if (isempty(p))
839 return false;
49dbfa7b 840
a2e03378
LP
841 return ascii_is_valid(p);
842}
49dbfa7b 843
a2e03378
LP
844bool documentation_url_is_valid(const char *url) {
845 const char *p;
846
847 if (isempty(url))
848 return false;
849
850 if (http_url_is_valid(url))
49dbfa7b
LP
851 return true;
852
a2e03378
LP
853 p = startswith(url, "file:/");
854 if (!p)
855 p = startswith(url, "info:");
856 if (!p)
857 p = startswith(url, "man:");
858
859 if (isempty(p))
860 return false;
861
862 return ascii_is_valid(p);
49dbfa7b 863}
9be346c9
HH
864
865bool in_initrd(void) {
73020ab2 866 static int saved = -1;
825c6fe5 867 struct statfs s;
8f33b5b8 868
825c6fe5
LP
869 if (saved >= 0)
870 return saved;
871
872 /* We make two checks here:
873 *
874 * 1. the flag file /etc/initrd-release must exist
875 * 2. the root file system must be a memory file system
876 *
877 * The second check is extra paranoia, since misdetecting an
878 * initrd can have bad bad consequences due the initrd
879 * emptying when transititioning to the main systemd.
880 */
881
882 saved = access("/etc/initrd-release", F_OK) >= 0 &&
883 statfs("/", &s) >= 0 &&
943aad8c 884 is_temporary_fs(&s);
9be346c9 885
8f33b5b8 886 return saved;
9be346c9 887}
069cfc85 888
0b507b17
LP
889bool string_is_safe(const char *p) {
890 const char *t;
891
6294aa76
LP
892 if (!p)
893 return false;
0b507b17
LP
894
895 for (t = p; *t; t++) {
01539d6e 896 if (*t > 0 && *t < ' ')
0b507b17
LP
897 return false;
898
843f6bf4 899 if (strchr("\\\"\'\x7f", *t))
0b507b17
LP
900 return false;
901 }
902
903 return true;
904}
cfbc22ab 905
a9e12476
KS
906/* hey glibc, APIs with callbacks without a user pointer are so useless */
907void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
1c574591 908 int (*compar) (const void *, const void *, void *), void *arg) {
a9e12476
KS
909 size_t l, u, idx;
910 const void *p;
911 int comparison;
912
913 l = 0;
914 u = nmemb;
915 while (l < u) {
916 idx = (l + u) / 2;
917 p = (void *)(((const char *) base) + (idx * size));
918 comparison = compar(key, p, arg);
919 if (comparison < 0)
920 u = idx;
921 else if (comparison > 0)
922 l = idx + 1;
923 else
924 return (void *)p;
925 }
926 return NULL;
927}
09017585 928
20f56fdd
DR
929void init_gettext(void) {
930 setlocale(LC_ALL, "");
931 textdomain(GETTEXT_PACKAGE);
932}
933
09017585
MS
934bool is_locale_utf8(void) {
935 const char *set;
936 static int cached_answer = -1;
937
938 if (cached_answer >= 0)
939 goto out;
940
941 if (!setlocale(LC_ALL, "")) {
942 cached_answer = true;
943 goto out;
944 }
945
946 set = nl_langinfo(CODESET);
947 if (!set) {
948 cached_answer = true;
949 goto out;
950 }
951
f168c273 952 if (streq(set, "UTF-8")) {
fee79e01
HH
953 cached_answer = true;
954 goto out;
955 }
956
6cf2f1d9
HH
957 /* For LC_CTYPE=="C" return true, because CTYPE is effectly
958 * unset and everything can do to UTF-8 nowadays. */
fee79e01
HH
959 set = setlocale(LC_CTYPE, NULL);
960 if (!set) {
961 cached_answer = true;
962 goto out;
963 }
964
6cf2f1d9
HH
965 /* Check result, but ignore the result if C was set
966 * explicitly. */
967 cached_answer =
9797f89b 968 STR_IN_SET(set, "C", "POSIX") &&
6cf2f1d9
HH
969 !getenv("LC_ALL") &&
970 !getenv("LC_CTYPE") &&
971 !getenv("LANG");
fee79e01 972
09017585 973out:
6cf2f1d9 974 return (bool) cached_answer;
09017585 975}
c339d977
MS
976
977const char *draw_special_char(DrawSpecialChar ch) {
978 static const char *draw_table[2][_DRAW_SPECIAL_CHAR_MAX] = {
6b01f1d3 979
c339d977 980 /* UTF-8 */ {
6b01f1d3 981 [DRAW_TREE_VERTICAL] = "\342\224\202 ", /* │ */
45a5ff0d
MS
982 [DRAW_TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */
983 [DRAW_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */
55c0b89c 984 [DRAW_TREE_SPACE] = " ", /* */
6b01f1d3
LP
985 [DRAW_TRIANGULAR_BULLET] = "\342\200\243", /* ‣ */
986 [DRAW_BLACK_CIRCLE] = "\342\227\217", /* ● */
987 [DRAW_ARROW] = "\342\206\222", /* → */
13f8b8cb 988 [DRAW_DASH] = "\342\200\223", /* – */
c339d977 989 },
6b01f1d3 990
c339d977 991 /* ASCII fallback */ {
6b01f1d3 992 [DRAW_TREE_VERTICAL] = "| ",
45a5ff0d
MS
993 [DRAW_TREE_BRANCH] = "|-",
994 [DRAW_TREE_RIGHT] = "`-",
55c0b89c 995 [DRAW_TREE_SPACE] = " ",
6b01f1d3
LP
996 [DRAW_TRIANGULAR_BULLET] = ">",
997 [DRAW_BLACK_CIRCLE] = "*",
998 [DRAW_ARROW] = "->",
13f8b8cb 999 [DRAW_DASH] = "-",
c339d977
MS
1000 }
1001 };
1002
1003 return draw_table[!is_locale_utf8()][ch];
1004}
409bc9c3 1005
240dbaa4
LP
1006int on_ac_power(void) {
1007 bool found_offline = false, found_online = false;
1008 _cleanup_closedir_ DIR *d = NULL;
1009
1010 d = opendir("/sys/class/power_supply");
1011 if (!d)
6d890034 1012 return errno == ENOENT ? true : -errno;
240dbaa4
LP
1013
1014 for (;;) {
1015 struct dirent *de;
240dbaa4
LP
1016 _cleanup_close_ int fd = -1, device = -1;
1017 char contents[6];
1018 ssize_t n;
240dbaa4 1019
3fd11280
FW
1020 errno = 0;
1021 de = readdir(d);
1022 if (!de && errno != 0)
1023 return -errno;
240dbaa4
LP
1024
1025 if (!de)
1026 break;
1027
a34bf9db 1028 if (hidden_file(de->d_name))
240dbaa4
LP
1029 continue;
1030
1031 device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
1032 if (device < 0) {
1033 if (errno == ENOENT || errno == ENOTDIR)
1034 continue;
1035
1036 return -errno;
1037 }
1038
1039 fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1040 if (fd < 0) {
1041 if (errno == ENOENT)
1042 continue;
1043
1044 return -errno;
1045 }
1046
1047 n = read(fd, contents, sizeof(contents));
1048 if (n < 0)
1049 return -errno;
1050
1051 if (n != 6 || memcmp(contents, "Mains\n", 6))
1052 continue;
1053
03e334a1 1054 safe_close(fd);
240dbaa4
LP
1055 fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1056 if (fd < 0) {
1057 if (errno == ENOENT)
1058 continue;
1059
1060 return -errno;
1061 }
1062
1063 n = read(fd, contents, sizeof(contents));
1064 if (n < 0)
1065 return -errno;
1066
1067 if (n != 2 || contents[1] != '\n')
1068 return -EIO;
1069
1070 if (contents[0] == '1') {
1071 found_online = true;
1072 break;
1073 } else if (contents[0] == '0')
1074 found_offline = true;
1075 else
1076 return -EIO;
1077 }
1078
1079 return found_online || !found_offline;
1080}
fabe5c0e 1081
ca2d3784
ZJS
1082void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
1083 size_t a, newalloc;
392d5b37
LP
1084 void *q;
1085
98088803 1086 assert(p);
e93c33d4
SL
1087 assert(allocated);
1088
392d5b37
LP
1089 if (*allocated >= need)
1090 return *p;
1091
ca2d3784
ZJS
1092 newalloc = MAX(need * 2, 64u / size);
1093 a = newalloc * size;
98088803
LP
1094
1095 /* check for overflows */
ca2d3784 1096 if (a < size * need)
98088803
LP
1097 return NULL;
1098
392d5b37
LP
1099 q = realloc(*p, a);
1100 if (!q)
1101 return NULL;
1102
1103 *p = q;
ca2d3784 1104 *allocated = newalloc;
392d5b37
LP
1105 return q;
1106}
aa96c6cb 1107
ca2d3784 1108void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) {
98088803 1109 size_t prev;
4545a231
DH
1110 uint8_t *q;
1111
98088803
LP
1112 assert(p);
1113 assert(allocated);
1114
1115 prev = *allocated;
1116
ca2d3784 1117 q = greedy_realloc(p, allocated, need, size);
4545a231
DH
1118 if (!q)
1119 return NULL;
1120
1121 if (*allocated > prev)
ca2d3784 1122 memzero(q + prev * size, (*allocated - prev) * size);
4545a231
DH
1123
1124 return q;
1125}
1126
aa96c6cb
LP
1127bool id128_is_valid(const char *s) {
1128 size_t i, l;
1129
1130 l = strlen(s);
1131 if (l == 32) {
1132
1133 /* Simple formatted 128bit hex string */
1134
1135 for (i = 0; i < l; i++) {
1136 char c = s[i];
1137
1138 if (!(c >= '0' && c <= '9') &&
1139 !(c >= 'a' && c <= 'z') &&
1140 !(c >= 'A' && c <= 'Z'))
1141 return false;
1142 }
1143
1144 } else if (l == 36) {
1145
1146 /* Formatted UUID */
1147
1148 for (i = 0; i < l; i++) {
1149 char c = s[i];
1150
1151 if ((i == 8 || i == 13 || i == 18 || i == 23)) {
1152 if (c != '-')
1153 return false;
1154 } else {
1155 if (!(c >= '0' && c <= '9') &&
1156 !(c >= 'a' && c <= 'z') &&
1157 !(c >= 'A' && c <= 'Z'))
1158 return false;
1159 }
1160 }
1161
1162 } else
1163 return false;
1164
1165 return true;
1166}
7085053a 1167
74df0fca 1168int shall_restore_state(void) {
1a299299 1169 _cleanup_free_ char *value = NULL;
74df0fca 1170 int r;
295edddf 1171
1a299299 1172 r = get_proc_cmdline_key("systemd.restore_state=", &value);
74df0fca
LP
1173 if (r < 0)
1174 return r;
1a299299
LP
1175 if (r == 0)
1176 return true;
295edddf 1177
1a299299 1178 return parse_boolean(value) != 0;
74df0fca
LP
1179}
1180
1181int proc_cmdline(char **ret) {
b5884878 1182 assert(ret);
295edddf 1183
75f86906 1184 if (detect_container() > 0)
b5884878
LP
1185 return get_process_cmdline(1, 0, false, ret);
1186 else
1187 return read_one_line_file("/proc/cmdline", ret);
295edddf 1188}
bc9fd78c 1189
059cb385 1190int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
141a79f4 1191 _cleanup_free_ char *line = NULL;
f32d2db1 1192 const char *p;
141a79f4
ZJS
1193 int r;
1194
059cb385
LP
1195 assert(parse_item);
1196
141a79f4
ZJS
1197 r = proc_cmdline(&line);
1198 if (r < 0)
b5884878 1199 return r;
141a79f4 1200
f32d2db1
LP
1201 p = line;
1202 for (;;) {
1203 _cleanup_free_ char *word = NULL;
1204 char *value = NULL;
141a79f4 1205
12ba2c44 1206 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
f32d2db1
LP
1207 if (r < 0)
1208 return r;
1209 if (r == 0)
1210 break;
141a79f4 1211
059cb385
LP
1212 /* Filter out arguments that are intended only for the
1213 * initrd */
1214 if (!in_initrd() && startswith(word, "rd."))
1215 continue;
1216
1217 value = strchr(word, '=');
1218 if (value)
1219 *(value++) = 0;
1220
1221 r = parse_item(word, value);
1222 if (r < 0)
141a79f4 1223 return r;
141a79f4
ZJS
1224 }
1225
1226 return 0;
1227}
1228
1a299299
LP
1229int get_proc_cmdline_key(const char *key, char **value) {
1230 _cleanup_free_ char *line = NULL, *ret = NULL;
1231 bool found = false;
1232 const char *p;
1233 int r;
1234
1235 assert(key);
1236
1237 r = proc_cmdline(&line);
1238 if (r < 0)
1239 return r;
1240
1241 p = line;
1242 for (;;) {
1243 _cleanup_free_ char *word = NULL;
1244 const char *e;
1245
12ba2c44 1246 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
1a299299
LP
1247 if (r < 0)
1248 return r;
1249 if (r == 0)
1250 break;
1251
1252 /* Filter out arguments that are intended only for the
1253 * initrd */
1254 if (!in_initrd() && startswith(word, "rd."))
1255 continue;
1256
1257 if (value) {
1258 e = startswith(word, key);
1259 if (!e)
1260 continue;
1261
1262 r = free_and_strdup(&ret, e);
1263 if (r < 0)
1264 return r;
1265
1266 found = true;
1267 } else {
1268 if (streq(word, key))
1269 found = true;
1270 }
1271 }
1272
1273 if (value) {
1274 *value = ret;
1275 ret = NULL;
1276 }
1277
1278 return found;
1279
1280}
1281
bc9fd78c
LP
1282int container_get_leader(const char *machine, pid_t *pid) {
1283 _cleanup_free_ char *s = NULL, *class = NULL;
1284 const char *p;
1285 pid_t leader;
1286 int r;
1287
1288 assert(machine);
1289 assert(pid);
1290
b9a8d250
LP
1291 if (!machine_name_is_valid(machine))
1292 return -EINVAL;
1293
63c372cb 1294 p = strjoina("/run/systemd/machines/", machine);
bc9fd78c
LP
1295 r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
1296 if (r == -ENOENT)
1297 return -EHOSTDOWN;
1298 if (r < 0)
1299 return r;
1300 if (!s)
1301 return -EIO;
1302
1303 if (!streq_ptr(class, "container"))
1304 return -EIO;
1305
1306 r = parse_pid(s, &leader);
1307 if (r < 0)
1308 return r;
1309 if (leader <= 1)
1310 return -EIO;
1311
1312 *pid = leader;
1313 return 0;
1314}
1315
671c3419
RM
1316int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
1317 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
359a06aa 1318 int rfd = -1;
bc9fd78c
LP
1319
1320 assert(pid >= 0);
bc9fd78c 1321
878cd7e9
LP
1322 if (mntns_fd) {
1323 const char *mntns;
a4475f57 1324
878cd7e9
LP
1325 mntns = procfs_file_alloca(pid, "ns/mnt");
1326 mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1327 if (mntnsfd < 0)
1328 return -errno;
1329 }
bc9fd78c 1330
878cd7e9
LP
1331 if (pidns_fd) {
1332 const char *pidns;
1333
1334 pidns = procfs_file_alloca(pid, "ns/pid");
1335 pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1336 if (pidnsfd < 0)
1337 return -errno;
1338 }
1339
1340 if (netns_fd) {
1341 const char *netns;
1342
1343 netns = procfs_file_alloca(pid, "ns/net");
1344 netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1345 if (netnsfd < 0)
1346 return -errno;
1347 }
1348
671c3419
RM
1349 if (userns_fd) {
1350 const char *userns;
1351
1352 userns = procfs_file_alloca(pid, "ns/user");
1353 usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1354 if (usernsfd < 0 && errno != ENOENT)
1355 return -errno;
1356 }
1357
878cd7e9
LP
1358 if (root_fd) {
1359 const char *root;
1360
1361 root = procfs_file_alloca(pid, "root");
1362 rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1363 if (rfd < 0)
1364 return -errno;
1365 }
1366
1367 if (pidns_fd)
1368 *pidns_fd = pidnsfd;
bc9fd78c 1369
878cd7e9
LP
1370 if (mntns_fd)
1371 *mntns_fd = mntnsfd;
1372
1373 if (netns_fd)
1374 *netns_fd = netnsfd;
1375
671c3419
RM
1376 if (userns_fd)
1377 *userns_fd = usernsfd;
1378
878cd7e9
LP
1379 if (root_fd)
1380 *root_fd = rfd;
1381
671c3419 1382 pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
bc9fd78c
LP
1383
1384 return 0;
1385}
1386
671c3419
RM
1387int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
1388 if (userns_fd >= 0) {
1389 /* Can't setns to your own userns, since then you could
1390 * escalate from non-root to root in your own namespace, so
1391 * check if namespaces equal before attempting to enter. */
1392 _cleanup_free_ char *userns_fd_path = NULL;
1393 int r;
1394 if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
1395 return -ENOMEM;
1396
1397 r = files_same(userns_fd_path, "/proc/self/ns/user");
1398 if (r < 0)
1399 return r;
1400 if (r)
1401 userns_fd = -1;
1402 }
bc9fd78c 1403
878cd7e9
LP
1404 if (pidns_fd >= 0)
1405 if (setns(pidns_fd, CLONE_NEWPID) < 0)
1406 return -errno;
a4475f57 1407
878cd7e9
LP
1408 if (mntns_fd >= 0)
1409 if (setns(mntns_fd, CLONE_NEWNS) < 0)
1410 return -errno;
bc9fd78c 1411
878cd7e9
LP
1412 if (netns_fd >= 0)
1413 if (setns(netns_fd, CLONE_NEWNET) < 0)
1414 return -errno;
bc9fd78c 1415
671c3419
RM
1416 if (userns_fd >= 0)
1417 if (setns(userns_fd, CLONE_NEWUSER) < 0)
1418 return -errno;
1419
878cd7e9
LP
1420 if (root_fd >= 0) {
1421 if (fchdir(root_fd) < 0)
1422 return -errno;
1423
1424 if (chroot(".") < 0)
1425 return -errno;
1426 }
bc9fd78c 1427
b4da6d6b 1428 return reset_uid_gid();
bc9fd78c 1429}
bf108e55 1430
ac45f971 1431unsigned long personality_from_string(const char *p) {
6afc95b7
LP
1432
1433 /* Parse a personality specifier. We introduce our own
1434 * identifiers that indicate specific ABIs, rather than just
1435 * hints regarding the register size, since we want to keep
1436 * things open for multiple locally supported ABIs for the
1437 * same register size. We try to reuse the ABI identifiers
1438 * used by libseccomp. */
1439
1440#if defined(__x86_64__)
1441
1442 if (streq(p, "x86"))
1443 return PER_LINUX32;
1444
1445 if (streq(p, "x86-64"))
1446 return PER_LINUX;
1447
1448#elif defined(__i386__)
1449
1450 if (streq(p, "x86"))
1451 return PER_LINUX;
7517f51e
HB
1452
1453#elif defined(__s390x__)
1454
1455 if (streq(p, "s390"))
1456 return PER_LINUX32;
1457
1458 if (streq(p, "s390x"))
1459 return PER_LINUX;
1460
1461#elif defined(__s390__)
1462
1463 if (streq(p, "s390"))
1464 return PER_LINUX;
6afc95b7
LP
1465#endif
1466
050f7277 1467 return PERSONALITY_INVALID;
6afc95b7 1468}
ac45f971
LP
1469
1470const char* personality_to_string(unsigned long p) {
1471
1472#if defined(__x86_64__)
1473
1474 if (p == PER_LINUX32)
1475 return "x86";
1476
1477 if (p == PER_LINUX)
1478 return "x86-64";
1479
1480#elif defined(__i386__)
1481
1482 if (p == PER_LINUX)
1483 return "x86";
7517f51e
HB
1484
1485#elif defined(__s390x__)
1486
1487 if (p == PER_LINUX)
1488 return "s390x";
1489
1490 if (p == PER_LINUX32)
1491 return "s390";
1492
1493#elif defined(__s390__)
1494
1495 if (p == PER_LINUX)
1496 return "s390";
1497
ac45f971
LP
1498#endif
1499
1500 return NULL;
1501}
1c231f56
LP
1502
1503uint64_t physical_memory(void) {
1504 long mem;
1505
1506 /* We return this as uint64_t in case we are running as 32bit
1507 * process on a 64bit kernel with huge amounts of memory */
1508
1509 mem = sysconf(_SC_PHYS_PAGES);
1510 assert(mem > 0);
1511
1512 return (uint64_t) mem * (uint64_t) page_size();
1513}
6db615c1 1514
966bff26 1515int update_reboot_param_file(const char *param) {
c5220a94
MO
1516 int r = 0;
1517
1518 if (param) {
4c1fc3e4 1519 r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE);
c5220a94 1520 if (r < 0)
e53fc357 1521 return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m");
c5220a94 1522 } else
e53fc357 1523 (void) unlink(REBOOT_PARAM_FILE);
c5220a94 1524
e53fc357 1525 return 0;
c5220a94 1526}
6d313367 1527
5261ba90
TT
1528int is_symlink(const char *path) {
1529 struct stat info;
1530
1531 if (lstat(path, &info) < 0)
1532 return -errno;
1533
be57e297
LP
1534 return !!S_ISLNK(info.st_mode);
1535}
5261ba90 1536
be57e297
LP
1537int is_dir(const char* path, bool follow) {
1538 struct stat st;
d1bddcec 1539 int r;
be57e297 1540
d1bddcec
LP
1541 if (follow)
1542 r = stat(path, &st);
1543 else
1544 r = lstat(path, &st);
1545 if (r < 0)
1546 return -errno;
be57e297
LP
1547
1548 return !!S_ISDIR(st.st_mode);
a0627f82 1549}
7629889c 1550
ce5b3ad4
SJ
1551int is_device_node(const char *path) {
1552 struct stat info;
1553
1554 if (lstat(path, &info) < 0)
1555 return -errno;
1556
1557 return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
1558}
1559
3d7415f4
LP
1560int syslog_parse_priority(const char **p, int *priority, bool with_facility) {
1561 int a = 0, b = 0, c = 0;
1562 int k;
1563
1564 assert(p);
1565 assert(*p);
1566 assert(priority);
1567
1568 if ((*p)[0] != '<')
1569 return 0;
1570
1571 if (!strchr(*p, '>'))
1572 return 0;
1573
1574 if ((*p)[2] == '>') {
1575 c = undecchar((*p)[1]);
1576 k = 3;
1577 } else if ((*p)[3] == '>') {
1578 b = undecchar((*p)[1]);
1579 c = undecchar((*p)[2]);
1580 k = 4;
1581 } else if ((*p)[4] == '>') {
1582 a = undecchar((*p)[1]);
1583 b = undecchar((*p)[2]);
1584 c = undecchar((*p)[3]);
1585 k = 5;
1586 } else
1587 return 0;
1588
1589 if (a < 0 || b < 0 || c < 0 ||
1590 (!with_facility && (a || b || c > 7)))
1591 return 0;
1592
1593 if (with_facility)
1594 *priority = a*100 + b*10 + c;
1595 else
1596 *priority = (*priority & LOG_FACMASK) | c;
1597
1598 *p += k;
1599 return 1;
1600}
9cad100e
BB
1601
1602ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) {
1603 size_t i;
1604
1605 if (!key)
1606 return -1;
1607
1608 for (i = 0; i < len; ++i)
1609 if (streq_ptr(table[i], key))
8c721f2b 1610 return (ssize_t) i;
9cad100e
BB
1611
1612 return -1;
1613}
1c8da044 1614
3f6fd1ba
LP
1615int version(void) {
1616 puts(PACKAGE_STRING "\n"
1617 SYSTEMD_FEATURES);
1618 return 0;
1619}
8dd4c05b
LP
1620
1621bool fdname_is_valid(const char *s) {
1622 const char *p;
1623
0a3bb96e 1624 /* Validates a name for $LISTEN_FDNAMES. We basically allow
8dd4c05b
LP
1625 * everything ASCII that's not a control character. Also, as
1626 * special exception the ":" character is not allowed, as we
0a3bb96e 1627 * use that as field separator in $LISTEN_FDNAMES.
8dd4c05b 1628 *
0a3bb96e
LP
1629 * Note that the empty string is explicitly allowed
1630 * here. However, we limit the length of the names to 255
1631 * characters. */
8dd4c05b
LP
1632
1633 if (!s)
1634 return false;
1635
1636 for (p = s; *p; p++) {
1637 if (*p < ' ')
1638 return false;
1639 if (*p >= 127)
1640 return false;
1641 if (*p == ':')
1642 return false;
1643 }
1644
1645 return p - s < 256;
1646}
257b0719
EV
1647
1648bool oom_score_adjust_is_valid(int oa) {
1649 return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX;
1650}