]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/util.c
networkd: Tunnel add support to configure key for VTI/VTI6 (#3532)
[thirdparty/systemd.git] / src / basic / util.c
CommitLineData
a7334b09
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
a7334b09
LP
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 14 Lesser General Public License for more details.
a7334b09 15
5430f7f2 16 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
11c3a366 20#include <alloca.h>
f6c2284a 21#include <dirent.h>
60918275 22#include <errno.h>
f6c2284a 23#include <fcntl.h>
f6c2284a
LP
24#include <sched.h>
25#include <signal.h>
26#include <stdarg.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
87d2c1ff 30#include <sys/mman.h>
f6c2284a 31#include <sys/prctl.h>
11c3a366
TA
32#include <sys/statfs.h>
33#include <sys/sysmacros.h>
f6c2284a 34#include <sys/types.h>
f6c2284a 35#include <unistd.h>
eef46c37 36
b5efdb8a 37#include "alloc-util.h"
3f6fd1ba 38#include "build.h"
f6c2284a 39#include "def.h"
cf0fbc49 40#include "dirent-util.h"
3ffd4af2 41#include "fd-util.h"
f6c2284a
LP
42#include "fileio.h"
43#include "formats-util.h"
f6c2284a
LP
44#include "hashmap.h"
45#include "hostname-util.h"
a9f5d454 46#include "log.h"
f6c2284a
LP
47#include "macro.h"
48#include "missing.h"
6bedfcbb 49#include "parse-util.h"
9eb977db 50#include "path-util.h"
0b452006 51#include "process-util.h"
11c3a366 52#include "set.h"
93cc7779 53#include "signal-util.h"
cf0fbc49 54#include "stat-util.h"
07630cea 55#include "string-util.h"
f6c2284a 56#include "strv.h"
93cc7779 57#include "time-util.h"
8612da97 58#include "umask-util.h"
b1d4f8e1 59#include "user-util.h"
4f5dd394 60#include "util.h"
56cf987f 61
012d7b42
ZJS
62/* Put this test here for a lack of better place */
63assert_cc(EAGAIN == EWOULDBLOCK);
64
9a0e6896
LP
65int saved_argc = 0;
66char **saved_argv = NULL;
dcd61450 67static int saved_in_initrd = -1;
9086e840 68
37f85e66 69size_t page_size(void) {
ec202eae 70 static thread_local size_t pgsz = 0;
37f85e66 71 long r;
72
87d2c1ff 73 if (_likely_(pgsz > 0))
37f85e66 74 return pgsz;
75
e67f47e5
LP
76 r = sysconf(_SC_PAGESIZE);
77 assert(r > 0);
37f85e66 78
79 pgsz = (size_t) r;
37f85e66 80 return pgsz;
81}
82
e801700e 83static int do_execute(char **directories, usec_t timeout, char *argv[]) {
49681057 84 _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
e801700e
ZJS
85 _cleanup_set_free_free_ Set *seen = NULL;
86 char **directory;
83cc030f 87
49681057
ZJS
88 /* We fork this all off from a child process so that we can
89 * somewhat cleanly make use of SIGALRM to set a time limit */
83cc030f 90
ce30c8dc
LP
91 (void) reset_all_signal_handlers();
92 (void) reset_signal_mask();
83cc030f 93
49681057 94 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
83cc030f 95
49681057
ZJS
96 pids = hashmap_new(NULL);
97 if (!pids)
98 return log_oom();
83cc030f 99
e801700e
ZJS
100 seen = set_new(&string_hash_ops);
101 if (!seen)
102 return log_oom();
83cc030f 103
e801700e
ZJS
104 STRV_FOREACH(directory, directories) {
105 _cleanup_closedir_ DIR *d;
106 struct dirent *de;
83cc030f 107
e801700e
ZJS
108 d = opendir(*directory);
109 if (!d) {
110 if (errno == ENOENT)
111 continue;
83cc030f 112
e801700e
ZJS
113 return log_error_errno(errno, "Failed to open directory %s: %m", *directory);
114 }
83cc030f 115
e801700e
ZJS
116 FOREACH_DIRENT(de, d, break) {
117 _cleanup_free_ char *path = NULL;
118 pid_t pid;
119 int r;
120
121 if (!dirent_is_file(de))
122 continue;
83cc030f 123
e801700e
ZJS
124 if (set_contains(seen, de->d_name)) {
125 log_debug("%1$s/%2$s skipped (%2$s was already seen).", *directory, de->d_name);
126 continue;
127 }
128
129 r = set_put_strdup(seen, de->d_name);
130 if (r < 0)
131 return log_oom();
132
133 path = strjoin(*directory, "/", de->d_name, NULL);
134 if (!path)
135 return log_oom();
136
137 if (null_or_empty_path(path)) {
138 log_debug("%s is empty (a mask).", path);
139 continue;
7034e9db 140 }
83cc030f 141
e801700e
ZJS
142 pid = fork();
143 if (pid < 0) {
144 log_error_errno(errno, "Failed to fork: %m");
145 continue;
146 } else if (pid == 0) {
147 char *_argv[2];
83cc030f 148
e801700e 149 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
83cc030f 150
e801700e
ZJS
151 if (!argv) {
152 _argv[0] = path;
153 _argv[1] = NULL;
154 argv = _argv;
155 } else
156 argv[0] = path;
157
158 execv(path, argv);
159 return log_error_errno(errno, "Failed to execute %s: %m", path);
160 }
161
162 log_debug("Spawned %s as " PID_FMT ".", path, pid);
83cc030f 163
4a0b58c4 164 r = hashmap_put(pids, PID_TO_PTR(pid), path);
e801700e
ZJS
165 if (r < 0)
166 return log_oom();
167 path = NULL;
168 }
49681057 169 }
83cc030f 170
49681057
ZJS
171 /* Abort execution of this process after the timout. We simply
172 * rely on SIGALRM as default action terminating the process,
173 * and turn on alarm(). */
83cc030f 174
49681057
ZJS
175 if (timeout != USEC_INFINITY)
176 alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
83cc030f 177
49681057
ZJS
178 while (!hashmap_isempty(pids)) {
179 _cleanup_free_ char *path = NULL;
180 pid_t pid;
aa62a893 181
4a0b58c4 182 pid = PTR_TO_PID(hashmap_first_key(pids));
49681057 183 assert(pid > 0);
83cc030f 184
4a0b58c4 185 path = hashmap_remove(pids, PID_TO_PTR(pid));
49681057 186 assert(path);
aa62a893 187
49681057
ZJS
188 wait_for_terminate_and_warn(path, pid, true);
189 }
aa62a893 190
49681057
ZJS
191 return 0;
192}
aa62a893 193
e801700e 194void execute_directories(const char* const* directories, usec_t timeout, char *argv[]) {
49681057
ZJS
195 pid_t executor_pid;
196 int r;
e801700e
ZJS
197 char *name;
198 char **dirs = (char**) directories;
199
200 assert(!strv_isempty(dirs));
83cc030f 201
e801700e
ZJS
202 name = basename(dirs[0]);
203 assert(!isempty(name));
aa62a893 204
e801700e
ZJS
205 /* Executes all binaries in the directories in parallel and waits
206 * for them to finish. Optionally a timeout is applied. If a file
207 * with the same name exists in more than one directory, the
208 * earliest one wins. */
83cc030f 209
49681057
ZJS
210 executor_pid = fork();
211 if (executor_pid < 0) {
212 log_error_errno(errno, "Failed to fork: %m");
213 return;
214
215 } else if (executor_pid == 0) {
e801700e 216 r = do_execute(dirs, timeout, argv);
49681057 217 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
aa62a893 218 }
83cc030f 219
e801700e 220 wait_for_terminate_and_warn(name, executor_pid, true);
83cc030f
LP
221}
222
a88c8750
TG
223bool plymouth_running(void) {
224 return access("/run/plymouth/pid", F_OK) >= 0;
225}
226
4d6d6518
LP
227bool display_is_local(const char *display) {
228 assert(display);
229
230 return
231 display[0] == ':' &&
232 display[1] >= '0' &&
233 display[1] <= '9';
234}
235
236int socket_from_display(const char *display, char **path) {
237 size_t k;
238 char *f, *c;
239
240 assert(display);
241 assert(path);
242
243 if (!display_is_local(display))
244 return -EINVAL;
245
246 k = strspn(display+1, "0123456789");
247
f8294e41 248 f = new(char, strlen("/tmp/.X11-unix/X") + k + 1);
4d6d6518
LP
249 if (!f)
250 return -ENOMEM;
251
252 c = stpcpy(f, "/tmp/.X11-unix/X");
253 memcpy(c, display+1, k);
254 c[k] = 0;
255
256 *path = f;
257
258 return 0;
259}
260
94959f0f
LP
261int block_get_whole_disk(dev_t d, dev_t *ret) {
262 char *p, *s;
263 int r;
264 unsigned n, m;
265
266 assert(ret);
267
268 /* If it has a queue this is good enough for us */
269 if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0)
270 return -ENOMEM;
271
272 r = access(p, F_OK);
273 free(p);
274
275 if (r >= 0) {
276 *ret = d;
277 return 0;
278 }
279
280 /* If it is a partition find the originating device */
281 if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0)
282 return -ENOMEM;
283
284 r = access(p, F_OK);
285 free(p);
286
287 if (r < 0)
288 return -ENOENT;
289
290 /* Get parent dev_t */
291 if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0)
292 return -ENOMEM;
293
294 r = read_one_line_file(p, &s);
295 free(p);
296
297 if (r < 0)
298 return r;
299
300 r = sscanf(s, "%u:%u", &m, &n);
301 free(s);
302
303 if (r != 2)
304 return -EINVAL;
305
306 /* Only return this if it is really good enough for us. */
307 if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0)
308 return -ENOMEM;
309
310 r = access(p, F_OK);
311 free(p);
312
313 if (r >= 0) {
314 *ret = makedev(m, n);
315 return 0;
316 }
317
318 return -ENOENT;
319}
320
65457142
FC
321bool kexec_loaded(void) {
322 bool loaded = false;
323 char *s;
324
325 if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) {
326 if (s[0] == '1')
327 loaded = true;
328 free(s);
329 }
330 return loaded;
331}
fb9de93d 332
87d2c1ff
LP
333int prot_from_flags(int flags) {
334
335 switch (flags & O_ACCMODE) {
336
337 case O_RDONLY:
338 return PROT_READ;
339
340 case O_WRONLY:
341 return PROT_WRITE;
342
343 case O_RDWR:
344 return PROT_READ|PROT_WRITE;
345
346 default:
347 return -EINVAL;
348 }
7c99e0c1 349}
689b9a22 350
9bdc770c 351int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
6bb92a16 352 bool stdout_is_tty, stderr_is_tty;
8a7c93d8
LP
353 pid_t parent_pid, agent_pid;
354 sigset_t ss, saved_ss;
6bb92a16
LP
355 unsigned n, i;
356 va_list ap;
357 char **l;
358
359 assert(pid);
360 assert(path);
361
6bb92a16
LP
362 /* Spawns a temporary TTY agent, making sure it goes away when
363 * we go away */
364
8a7c93d8
LP
365 parent_pid = getpid();
366
367 /* First we temporarily block all signals, so that the new
368 * child has them blocked initially. This way, we can be sure
369 * that SIGTERMs are not lost we might send to the agent. */
370 assert_se(sigfillset(&ss) >= 0);
371 assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0);
372
6bb92a16 373 agent_pid = fork();
8a7c93d8
LP
374 if (agent_pid < 0) {
375 assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
6bb92a16 376 return -errno;
8a7c93d8 377 }
6bb92a16
LP
378
379 if (agent_pid != 0) {
8a7c93d8 380 assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
6bb92a16
LP
381 *pid = agent_pid;
382 return 0;
383 }
384
385 /* In the child:
386 *
387 * Make sure the agent goes away when the parent dies */
388 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
389 _exit(EXIT_FAILURE);
390
8a7c93d8
LP
391 /* Make sure we actually can kill the agent, if we need to, in
392 * case somebody invoked us from a shell script that trapped
393 * SIGTERM or so... */
ce30c8dc
LP
394 (void) reset_all_signal_handlers();
395 (void) reset_signal_mask();
8a7c93d8 396
6bb92a16 397 /* Check whether our parent died before we were able
8a7c93d8 398 * to set the death signal and unblock the signals */
6bb92a16
LP
399 if (getppid() != parent_pid)
400 _exit(EXIT_SUCCESS);
401
402 /* Don't leak fds to the agent */
9bdc770c 403 close_all_fds(except, n_except);
6bb92a16
LP
404
405 stdout_is_tty = isatty(STDOUT_FILENO);
406 stderr_is_tty = isatty(STDERR_FILENO);
407
408 if (!stdout_is_tty || !stderr_is_tty) {
8a7c93d8
LP
409 int fd;
410
6bb92a16
LP
411 /* Detach from stdout/stderr. and reopen
412 * /dev/tty for them. This is important to
413 * ensure that when systemctl is started via
414 * popen() or a similar call that expects to
415 * read EOF we actually do generate EOF and
416 * not delay this indefinitely by because we
417 * keep an unused copy of stdin around. */
418 fd = open("/dev/tty", O_WRONLY);
419 if (fd < 0) {
56f64d95 420 log_error_errno(errno, "Failed to open /dev/tty: %m");
6bb92a16
LP
421 _exit(EXIT_FAILURE);
422 }
423
94edd38e
ZJS
424 if (!stdout_is_tty && dup2(fd, STDOUT_FILENO) < 0) {
425 log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
426 _exit(EXIT_FAILURE);
427 }
6bb92a16 428
94edd38e
ZJS
429 if (!stderr_is_tty && dup2(fd, STDERR_FILENO) < 0) {
430 log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
431 _exit(EXIT_FAILURE);
432 }
6bb92a16 433
94edd38e 434 if (fd > STDERR_FILENO)
6bb92a16
LP
435 close(fd);
436 }
437
438 /* Count arguments */
439 va_start(ap, path);
440 for (n = 0; va_arg(ap, char*); n++)
441 ;
442 va_end(ap);
443
444 /* Allocate strv */
445 l = alloca(sizeof(char *) * (n + 1));
446
447 /* Fill in arguments */
448 va_start(ap, path);
449 for (i = 0; i <= n; i++)
450 l[i] = va_arg(ap, char*);
451 va_end(ap);
452
453 execv(path, l);
454 _exit(EXIT_FAILURE);
455}
68faf98c 456
9be346c9 457bool in_initrd(void) {
825c6fe5 458 struct statfs s;
8f33b5b8 459
dcd61450
IS
460 if (saved_in_initrd >= 0)
461 return saved_in_initrd;
825c6fe5
LP
462
463 /* We make two checks here:
464 *
465 * 1. the flag file /etc/initrd-release must exist
466 * 2. the root file system must be a memory file system
467 *
468 * The second check is extra paranoia, since misdetecting an
469 * initrd can have bad bad consequences due the initrd
470 * emptying when transititioning to the main systemd.
471 */
472
dcd61450
IS
473 saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 &&
474 statfs("/", &s) >= 0 &&
475 is_temporary_fs(&s);
9be346c9 476
dcd61450
IS
477 return saved_in_initrd;
478}
479
480void in_initrd_force(bool value) {
481 saved_in_initrd = value;
9be346c9 482}
069cfc85 483
a9e12476
KS
484/* hey glibc, APIs with callbacks without a user pointer are so useless */
485void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
1c574591 486 int (*compar) (const void *, const void *, void *), void *arg) {
a9e12476
KS
487 size_t l, u, idx;
488 const void *p;
489 int comparison;
490
491 l = 0;
492 u = nmemb;
493 while (l < u) {
494 idx = (l + u) / 2;
495 p = (void *)(((const char *) base) + (idx * size));
496 comparison = compar(key, p, arg);
497 if (comparison < 0)
498 u = idx;
499 else if (comparison > 0)
500 l = idx + 1;
501 else
502 return (void *)p;
503 }
504 return NULL;
505}
09017585 506
240dbaa4
LP
507int on_ac_power(void) {
508 bool found_offline = false, found_online = false;
509 _cleanup_closedir_ DIR *d = NULL;
510
511 d = opendir("/sys/class/power_supply");
512 if (!d)
6d890034 513 return errno == ENOENT ? true : -errno;
240dbaa4
LP
514
515 for (;;) {
516 struct dirent *de;
240dbaa4
LP
517 _cleanup_close_ int fd = -1, device = -1;
518 char contents[6];
519 ssize_t n;
240dbaa4 520
3fd11280
FW
521 errno = 0;
522 de = readdir(d);
b3267152 523 if (!de && errno > 0)
3fd11280 524 return -errno;
240dbaa4
LP
525
526 if (!de)
527 break;
528
55cdd057 529 if (hidden_or_backup_file(de->d_name))
240dbaa4
LP
530 continue;
531
532 device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
533 if (device < 0) {
534 if (errno == ENOENT || errno == ENOTDIR)
535 continue;
536
537 return -errno;
538 }
539
540 fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
541 if (fd < 0) {
542 if (errno == ENOENT)
543 continue;
544
545 return -errno;
546 }
547
548 n = read(fd, contents, sizeof(contents));
549 if (n < 0)
550 return -errno;
551
552 if (n != 6 || memcmp(contents, "Mains\n", 6))
553 continue;
554
03e334a1 555 safe_close(fd);
240dbaa4
LP
556 fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
557 if (fd < 0) {
558 if (errno == ENOENT)
559 continue;
560
561 return -errno;
562 }
563
564 n = read(fd, contents, sizeof(contents));
565 if (n < 0)
566 return -errno;
567
568 if (n != 2 || contents[1] != '\n')
569 return -EIO;
570
571 if (contents[0] == '1') {
572 found_online = true;
573 break;
574 } else if (contents[0] == '0')
575 found_offline = true;
576 else
577 return -EIO;
578 }
579
580 return found_online || !found_offline;
581}
fabe5c0e 582
aa96c6cb
LP
583bool id128_is_valid(const char *s) {
584 size_t i, l;
585
586 l = strlen(s);
587 if (l == 32) {
588
589 /* Simple formatted 128bit hex string */
590
591 for (i = 0; i < l; i++) {
592 char c = s[i];
593
594 if (!(c >= '0' && c <= '9') &&
595 !(c >= 'a' && c <= 'z') &&
596 !(c >= 'A' && c <= 'Z'))
597 return false;
598 }
599
600 } else if (l == 36) {
601
602 /* Formatted UUID */
603
604 for (i = 0; i < l; i++) {
605 char c = s[i];
606
607 if ((i == 8 || i == 13 || i == 18 || i == 23)) {
608 if (c != '-')
609 return false;
610 } else {
611 if (!(c >= '0' && c <= '9') &&
612 !(c >= 'a' && c <= 'z') &&
613 !(c >= 'A' && c <= 'Z'))
614 return false;
615 }
616 }
617
618 } else
619 return false;
620
621 return true;
622}
7085053a 623
bc9fd78c
LP
624int container_get_leader(const char *machine, pid_t *pid) {
625 _cleanup_free_ char *s = NULL, *class = NULL;
626 const char *p;
627 pid_t leader;
628 int r;
629
630 assert(machine);
631 assert(pid);
632
b9a8d250
LP
633 if (!machine_name_is_valid(machine))
634 return -EINVAL;
635
63c372cb 636 p = strjoina("/run/systemd/machines/", machine);
bc9fd78c
LP
637 r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
638 if (r == -ENOENT)
639 return -EHOSTDOWN;
640 if (r < 0)
641 return r;
642 if (!s)
643 return -EIO;
644
645 if (!streq_ptr(class, "container"))
646 return -EIO;
647
648 r = parse_pid(s, &leader);
649 if (r < 0)
650 return r;
651 if (leader <= 1)
652 return -EIO;
653
654 *pid = leader;
655 return 0;
656}
657
671c3419
RM
658int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
659 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
359a06aa 660 int rfd = -1;
bc9fd78c
LP
661
662 assert(pid >= 0);
bc9fd78c 663
878cd7e9
LP
664 if (mntns_fd) {
665 const char *mntns;
a4475f57 666
878cd7e9
LP
667 mntns = procfs_file_alloca(pid, "ns/mnt");
668 mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
669 if (mntnsfd < 0)
670 return -errno;
671 }
bc9fd78c 672
878cd7e9
LP
673 if (pidns_fd) {
674 const char *pidns;
675
676 pidns = procfs_file_alloca(pid, "ns/pid");
677 pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
678 if (pidnsfd < 0)
679 return -errno;
680 }
681
682 if (netns_fd) {
683 const char *netns;
684
685 netns = procfs_file_alloca(pid, "ns/net");
686 netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
687 if (netnsfd < 0)
688 return -errno;
689 }
690
671c3419
RM
691 if (userns_fd) {
692 const char *userns;
693
694 userns = procfs_file_alloca(pid, "ns/user");
695 usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
696 if (usernsfd < 0 && errno != ENOENT)
697 return -errno;
698 }
699
878cd7e9
LP
700 if (root_fd) {
701 const char *root;
702
703 root = procfs_file_alloca(pid, "root");
704 rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
705 if (rfd < 0)
706 return -errno;
707 }
708
709 if (pidns_fd)
710 *pidns_fd = pidnsfd;
bc9fd78c 711
878cd7e9
LP
712 if (mntns_fd)
713 *mntns_fd = mntnsfd;
714
715 if (netns_fd)
716 *netns_fd = netnsfd;
717
671c3419
RM
718 if (userns_fd)
719 *userns_fd = usernsfd;
720
878cd7e9
LP
721 if (root_fd)
722 *root_fd = rfd;
723
671c3419 724 pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
bc9fd78c
LP
725
726 return 0;
727}
728
671c3419
RM
729int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
730 if (userns_fd >= 0) {
731 /* Can't setns to your own userns, since then you could
732 * escalate from non-root to root in your own namespace, so
733 * check if namespaces equal before attempting to enter. */
734 _cleanup_free_ char *userns_fd_path = NULL;
735 int r;
736 if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
737 return -ENOMEM;
738
739 r = files_same(userns_fd_path, "/proc/self/ns/user");
740 if (r < 0)
741 return r;
742 if (r)
743 userns_fd = -1;
744 }
bc9fd78c 745
878cd7e9
LP
746 if (pidns_fd >= 0)
747 if (setns(pidns_fd, CLONE_NEWPID) < 0)
748 return -errno;
a4475f57 749
878cd7e9
LP
750 if (mntns_fd >= 0)
751 if (setns(mntns_fd, CLONE_NEWNS) < 0)
752 return -errno;
bc9fd78c 753
878cd7e9
LP
754 if (netns_fd >= 0)
755 if (setns(netns_fd, CLONE_NEWNET) < 0)
756 return -errno;
bc9fd78c 757
671c3419
RM
758 if (userns_fd >= 0)
759 if (setns(userns_fd, CLONE_NEWUSER) < 0)
760 return -errno;
761
878cd7e9
LP
762 if (root_fd >= 0) {
763 if (fchdir(root_fd) < 0)
764 return -errno;
765
766 if (chroot(".") < 0)
767 return -errno;
768 }
bc9fd78c 769
b4da6d6b 770 return reset_uid_gid();
bc9fd78c 771}
bf108e55 772
1c231f56
LP
773uint64_t physical_memory(void) {
774 long mem;
775
776 /* We return this as uint64_t in case we are running as 32bit
777 * process on a 64bit kernel with huge amounts of memory */
778
779 mem = sysconf(_SC_PHYS_PAGES);
780 assert(mem > 0);
781
782 return (uint64_t) mem * (uint64_t) page_size();
783}
6db615c1 784
27c06cb5
LP
785int update_reboot_parameter_and_warn(const char *param) {
786 int r;
c5220a94 787
27c06cb5
LP
788 if (isempty(param)) {
789 if (unlink("/run/systemd/reboot-param") < 0) {
790 if (errno == ENOENT)
791 return 0;
792
793 return log_warning_errno(errno, "Failed to unlink reboot parameter file: %m");
794 }
795
796 return 0;
797 }
798
78e334b5 799 RUN_WITH_UMASK(0022) {
27c06cb5 800 r = write_string_file("/run/systemd/reboot-param", param, WRITE_STRING_FILE_CREATE);
78e334b5
ZJS
801 if (r < 0)
802 return log_warning_errno(r, "Failed to write reboot parameter file: %m");
803 }
c5220a94 804
e53fc357 805 return 0;
c5220a94 806}
6d313367 807
3f6fd1ba
LP
808int version(void) {
809 puts(PACKAGE_STRING "\n"
810 SYSTEMD_FEATURES);
811 return 0;
812}