1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
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
11 (at your option) any later version.
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
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
31 #include <linux/magic.h>
32 #include <linux/oom.h>
33 #include <linux/sched.h>
44 #include <sys/ioctl.h>
46 #include <sys/mount.h>
47 #include <sys/personality.h>
48 #include <sys/prctl.h>
50 #include <sys/statvfs.h>
52 #include <sys/types.h>
53 #include <sys/utsname.h>
59 /* When we include libgen.h because we need dirname() we immediately
60 * undefine basename() since libgen.h defines it as a macro to the
61 * POSIX version which is really broken. We prefer GNU basename(). */
65 #ifdef HAVE_SYS_AUXV_H
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! */
75 #include "device-nodes.h"
78 #include "exit-status.h"
81 #include "formats-util.h"
84 #include "hostname-util.h"
90 #include "hexdecoct.h"
91 #include "parse-util.h"
92 #include "path-util.h"
93 #include "process-util.h"
94 #include "random-util.h"
95 #include "signal-util.h"
96 #include "sparse-endian.h"
97 #include "string-table.h"
98 #include "string-util.h"
100 #include "terminal-util.h"
101 #include "user-util.h"
105 #include "dirent-util.h"
106 #include "stat-util.h"
108 /* Put this test here for a lack of better place */
109 assert_cc(EAGAIN
== EWOULDBLOCK
);
112 char **saved_argv
= NULL
;
114 size_t page_size(void) {
115 static thread_local
size_t pgsz
= 0;
118 if (_likely_(pgsz
> 0))
121 r
= sysconf(_SC_PAGESIZE
);
128 bool fstype_is_network(const char *fstype
) {
129 static const char table
[] =
144 x
= startswith(fstype
, "fuse.");
148 return nulstr_contains(table
, fstype
);
151 void rename_process(const char name
[8]) {
154 /* This is a like a poor man's setproctitle(). It changes the
155 * comm field, argv[0], and also the glibc's internally used
156 * name of the process. For the first one a limit of 16 chars
157 * applies, to the second one usually one of 10 (i.e. length
158 * of "/sbin/init"), to the third one one of 7 (i.e. length of
159 * "systemd"). If you pass a longer string it will be
162 prctl(PR_SET_NAME
, name
);
164 if (program_invocation_name
)
165 strncpy(program_invocation_name
, name
, strlen(program_invocation_name
));
167 if (saved_argc
> 0) {
171 strncpy(saved_argv
[0], name
, strlen(saved_argv
[0]));
173 for (i
= 1; i
< saved_argc
; i
++) {
177 memzero(saved_argv
[i
], strlen(saved_argv
[i
]));
182 int running_in_chroot(void) {
185 ret
= files_same("/proc/1/root", "/");
192 noreturn
void freeze(void) {
194 /* Make sure nobody waits for us on a socket anymore */
195 close_all_fds(NULL
, 0);
203 static int do_execute(char **directories
, usec_t timeout
, char *argv
[]) {
204 _cleanup_hashmap_free_free_ Hashmap
*pids
= NULL
;
205 _cleanup_set_free_free_ Set
*seen
= NULL
;
208 /* We fork this all off from a child process so that we can
209 * somewhat cleanly make use of SIGALRM to set a time limit */
211 (void) reset_all_signal_handlers();
212 (void) reset_signal_mask();
214 assert_se(prctl(PR_SET_PDEATHSIG
, SIGTERM
) == 0);
216 pids
= hashmap_new(NULL
);
220 seen
= set_new(&string_hash_ops
);
224 STRV_FOREACH(directory
, directories
) {
225 _cleanup_closedir_
DIR *d
;
228 d
= opendir(*directory
);
233 return log_error_errno(errno
, "Failed to open directory %s: %m", *directory
);
236 FOREACH_DIRENT(de
, d
, break) {
237 _cleanup_free_
char *path
= NULL
;
241 if (!dirent_is_file(de
))
244 if (set_contains(seen
, de
->d_name
)) {
245 log_debug("%1$s/%2$s skipped (%2$s was already seen).", *directory
, de
->d_name
);
249 r
= set_put_strdup(seen
, de
->d_name
);
253 path
= strjoin(*directory
, "/", de
->d_name
, NULL
);
257 if (null_or_empty_path(path
)) {
258 log_debug("%s is empty (a mask).", path
);
264 log_error_errno(errno
, "Failed to fork: %m");
266 } else if (pid
== 0) {
269 assert_se(prctl(PR_SET_PDEATHSIG
, SIGTERM
) == 0);
279 return log_error_errno(errno
, "Failed to execute %s: %m", path
);
282 log_debug("Spawned %s as " PID_FMT
".", path
, pid
);
284 r
= hashmap_put(pids
, UINT_TO_PTR(pid
), path
);
291 /* Abort execution of this process after the timout. We simply
292 * rely on SIGALRM as default action terminating the process,
293 * and turn on alarm(). */
295 if (timeout
!= USEC_INFINITY
)
296 alarm((timeout
+ USEC_PER_SEC
- 1) / USEC_PER_SEC
);
298 while (!hashmap_isempty(pids
)) {
299 _cleanup_free_
char *path
= NULL
;
302 pid
= PTR_TO_UINT(hashmap_first_key(pids
));
305 path
= hashmap_remove(pids
, UINT_TO_PTR(pid
));
308 wait_for_terminate_and_warn(path
, pid
, true);
314 void execute_directories(const char* const* directories
, usec_t timeout
, char *argv
[]) {
318 char **dirs
= (char**) directories
;
320 assert(!strv_isempty(dirs
));
322 name
= basename(dirs
[0]);
323 assert(!isempty(name
));
325 /* Executes all binaries in the directories in parallel and waits
326 * for them to finish. Optionally a timeout is applied. If a file
327 * with the same name exists in more than one directory, the
328 * earliest one wins. */
330 executor_pid
= fork();
331 if (executor_pid
< 0) {
332 log_error_errno(errno
, "Failed to fork: %m");
335 } else if (executor_pid
== 0) {
336 r
= do_execute(dirs
, timeout
, argv
);
337 _exit(r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
);
340 wait_for_terminate_and_warn(name
, executor_pid
, true);
343 bool plymouth_running(void) {
344 return access("/run/plymouth/pid", F_OK
) >= 0;
347 bool display_is_local(const char *display
) {
356 int socket_from_display(const char *display
, char **path
) {
363 if (!display_is_local(display
))
366 k
= strspn(display
+1, "0123456789");
368 f
= new(char, strlen("/tmp/.X11-unix/X") + k
+ 1);
372 c
= stpcpy(f
, "/tmp/.X11-unix/X");
373 memcpy(c
, display
+1, k
);
381 int glob_exists(const char *path
) {
382 _cleanup_globfree_ glob_t g
= {};
388 k
= glob(path
, GLOB_NOSORT
|GLOB_BRACE
, NULL
, &g
);
390 if (k
== GLOB_NOMATCH
)
392 else if (k
== GLOB_NOSPACE
)
395 return !strv_isempty(g
.gl_pathv
);
397 return errno
? -errno
: -EIO
;
400 int glob_extend(char ***strv
, const char *path
) {
401 _cleanup_globfree_ glob_t g
= {};
406 k
= glob(path
, GLOB_NOSORT
|GLOB_BRACE
, NULL
, &g
);
408 if (k
== GLOB_NOMATCH
)
410 else if (k
== GLOB_NOSPACE
)
412 else if (k
!= 0 || strv_isempty(g
.gl_pathv
))
413 return errno
? -errno
: -EIO
;
415 STRV_FOREACH(p
, g
.gl_pathv
) {
416 k
= strv_extend(strv
, *p
);
424 bool is_main_thread(void) {
425 static thread_local
int cached
= 0;
427 if (_unlikely_(cached
== 0))
428 cached
= getpid() == gettid() ? 1 : -1;
433 int block_get_whole_disk(dev_t d
, dev_t
*ret
) {
440 /* If it has a queue this is good enough for us */
441 if (asprintf(&p
, "/sys/dev/block/%u:%u/queue", major(d
), minor(d
)) < 0)
452 /* If it is a partition find the originating device */
453 if (asprintf(&p
, "/sys/dev/block/%u:%u/partition", major(d
), minor(d
)) < 0)
462 /* Get parent dev_t */
463 if (asprintf(&p
, "/sys/dev/block/%u:%u/../dev", major(d
), minor(d
)) < 0)
466 r
= read_one_line_file(p
, &s
);
472 r
= sscanf(s
, "%u:%u", &m
, &n
);
478 /* Only return this if it is really good enough for us. */
479 if (asprintf(&p
, "/sys/dev/block/%u:%u/queue", m
, n
) < 0)
486 *ret
= makedev(m
, n
);
493 static const char *const ioprio_class_table
[] = {
494 [IOPRIO_CLASS_NONE
] = "none",
495 [IOPRIO_CLASS_RT
] = "realtime",
496 [IOPRIO_CLASS_BE
] = "best-effort",
497 [IOPRIO_CLASS_IDLE
] = "idle"
500 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class
, int, INT_MAX
);
502 static const char *const sigchld_code_table
[] = {
503 [CLD_EXITED
] = "exited",
504 [CLD_KILLED
] = "killed",
505 [CLD_DUMPED
] = "dumped",
506 [CLD_TRAPPED
] = "trapped",
507 [CLD_STOPPED
] = "stopped",
508 [CLD_CONTINUED
] = "continued",
511 DEFINE_STRING_TABLE_LOOKUP(sigchld_code
, int);
513 static const char *const log_facility_unshifted_table
[LOG_NFACILITIES
] = {
514 [LOG_FAC(LOG_KERN
)] = "kern",
515 [LOG_FAC(LOG_USER
)] = "user",
516 [LOG_FAC(LOG_MAIL
)] = "mail",
517 [LOG_FAC(LOG_DAEMON
)] = "daemon",
518 [LOG_FAC(LOG_AUTH
)] = "auth",
519 [LOG_FAC(LOG_SYSLOG
)] = "syslog",
520 [LOG_FAC(LOG_LPR
)] = "lpr",
521 [LOG_FAC(LOG_NEWS
)] = "news",
522 [LOG_FAC(LOG_UUCP
)] = "uucp",
523 [LOG_FAC(LOG_CRON
)] = "cron",
524 [LOG_FAC(LOG_AUTHPRIV
)] = "authpriv",
525 [LOG_FAC(LOG_FTP
)] = "ftp",
526 [LOG_FAC(LOG_LOCAL0
)] = "local0",
527 [LOG_FAC(LOG_LOCAL1
)] = "local1",
528 [LOG_FAC(LOG_LOCAL2
)] = "local2",
529 [LOG_FAC(LOG_LOCAL3
)] = "local3",
530 [LOG_FAC(LOG_LOCAL4
)] = "local4",
531 [LOG_FAC(LOG_LOCAL5
)] = "local5",
532 [LOG_FAC(LOG_LOCAL6
)] = "local6",
533 [LOG_FAC(LOG_LOCAL7
)] = "local7"
536 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted
, int, LOG_FAC(~0));
538 bool log_facility_unshifted_is_valid(int facility
) {
539 return facility
>= 0 && facility
<= LOG_FAC(~0);
542 static const char *const log_level_table
[] = {
543 [LOG_EMERG
] = "emerg",
544 [LOG_ALERT
] = "alert",
547 [LOG_WARNING
] = "warning",
548 [LOG_NOTICE
] = "notice",
550 [LOG_DEBUG
] = "debug"
553 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level
, int, LOG_DEBUG
);
555 bool log_level_is_valid(int level
) {
556 return level
>= 0 && level
<= LOG_DEBUG
;
559 static const char* const sched_policy_table
[] = {
560 [SCHED_OTHER
] = "other",
561 [SCHED_BATCH
] = "batch",
562 [SCHED_IDLE
] = "idle",
563 [SCHED_FIFO
] = "fifo",
567 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy
, int, INT_MAX
);
569 bool kexec_loaded(void) {
573 if (read_one_line_file("/sys/kernel/kexec_loaded", &s
) >= 0) {
581 int prot_from_flags(int flags
) {
583 switch (flags
& O_ACCMODE
) {
592 return PROT_READ
|PROT_WRITE
;
599 void* memdup(const void *p
, size_t l
) {
612 int fork_agent(pid_t
*pid
, const int except
[], unsigned n_except
, const char *path
, ...) {
613 bool stdout_is_tty
, stderr_is_tty
;
614 pid_t parent_pid
, agent_pid
;
615 sigset_t ss
, saved_ss
;
623 /* Spawns a temporary TTY agent, making sure it goes away when
626 parent_pid
= getpid();
628 /* First we temporarily block all signals, so that the new
629 * child has them blocked initially. This way, we can be sure
630 * that SIGTERMs are not lost we might send to the agent. */
631 assert_se(sigfillset(&ss
) >= 0);
632 assert_se(sigprocmask(SIG_SETMASK
, &ss
, &saved_ss
) >= 0);
636 assert_se(sigprocmask(SIG_SETMASK
, &saved_ss
, NULL
) >= 0);
640 if (agent_pid
!= 0) {
641 assert_se(sigprocmask(SIG_SETMASK
, &saved_ss
, NULL
) >= 0);
648 * Make sure the agent goes away when the parent dies */
649 if (prctl(PR_SET_PDEATHSIG
, SIGTERM
) < 0)
652 /* Make sure we actually can kill the agent, if we need to, in
653 * case somebody invoked us from a shell script that trapped
654 * SIGTERM or so... */
655 (void) reset_all_signal_handlers();
656 (void) reset_signal_mask();
658 /* Check whether our parent died before we were able
659 * to set the death signal and unblock the signals */
660 if (getppid() != parent_pid
)
663 /* Don't leak fds to the agent */
664 close_all_fds(except
, n_except
);
666 stdout_is_tty
= isatty(STDOUT_FILENO
);
667 stderr_is_tty
= isatty(STDERR_FILENO
);
669 if (!stdout_is_tty
|| !stderr_is_tty
) {
672 /* Detach from stdout/stderr. and reopen
673 * /dev/tty for them. This is important to
674 * ensure that when systemctl is started via
675 * popen() or a similar call that expects to
676 * read EOF we actually do generate EOF and
677 * not delay this indefinitely by because we
678 * keep an unused copy of stdin around. */
679 fd
= open("/dev/tty", O_WRONLY
);
681 log_error_errno(errno
, "Failed to open /dev/tty: %m");
686 dup2(fd
, STDOUT_FILENO
);
689 dup2(fd
, STDERR_FILENO
);
695 /* Count arguments */
697 for (n
= 0; va_arg(ap
, char*); n
++)
702 l
= alloca(sizeof(char *) * (n
+ 1));
704 /* Fill in arguments */
706 for (i
= 0; i
<= n
; i
++)
707 l
[i
] = va_arg(ap
, char*);
714 bool http_etag_is_valid(const char *etag
) {
718 if (!endswith(etag
, "\""))
721 if (!startswith(etag
, "\"") && !startswith(etag
, "W/\""))
727 bool http_url_is_valid(const char *url
) {
733 p
= startswith(url
, "http://");
735 p
= startswith(url
, "https://");
742 return ascii_is_valid(p
);
745 bool documentation_url_is_valid(const char *url
) {
751 if (http_url_is_valid(url
))
754 p
= startswith(url
, "file:/");
756 p
= startswith(url
, "info:");
758 p
= startswith(url
, "man:");
763 return ascii_is_valid(p
);
766 bool in_initrd(void) {
767 static int saved
= -1;
773 /* We make two checks here:
775 * 1. the flag file /etc/initrd-release must exist
776 * 2. the root file system must be a memory file system
778 * The second check is extra paranoia, since misdetecting an
779 * initrd can have bad bad consequences due the initrd
780 * emptying when transititioning to the main systemd.
783 saved
= access("/etc/initrd-release", F_OK
) >= 0 &&
784 statfs("/", &s
) >= 0 &&
790 /* hey glibc, APIs with callbacks without a user pointer are so useless */
791 void *xbsearch_r(const void *key
, const void *base
, size_t nmemb
, size_t size
,
792 int (*compar
) (const void *, const void *, void *), void *arg
) {
801 p
= (void *)(((const char *) base
) + (idx
* size
));
802 comparison
= compar(key
, p
, arg
);
805 else if (comparison
> 0)
813 void init_gettext(void) {
814 setlocale(LC_ALL
, "");
815 textdomain(GETTEXT_PACKAGE
);
818 bool is_locale_utf8(void) {
820 static int cached_answer
= -1;
822 if (cached_answer
>= 0)
825 if (!setlocale(LC_ALL
, "")) {
826 cached_answer
= true;
830 set
= nl_langinfo(CODESET
);
832 cached_answer
= true;
836 if (streq(set
, "UTF-8")) {
837 cached_answer
= true;
841 /* For LC_CTYPE=="C" return true, because CTYPE is effectly
842 * unset and everything can do to UTF-8 nowadays. */
843 set
= setlocale(LC_CTYPE
, NULL
);
845 cached_answer
= true;
849 /* Check result, but ignore the result if C was set
852 STR_IN_SET(set
, "C", "POSIX") &&
854 !getenv("LC_CTYPE") &&
858 return (bool) cached_answer
;
861 const char *draw_special_char(DrawSpecialChar ch
) {
862 static const char *draw_table
[2][_DRAW_SPECIAL_CHAR_MAX
] = {
865 [DRAW_TREE_VERTICAL
] = "\342\224\202 ", /* │ */
866 [DRAW_TREE_BRANCH
] = "\342\224\234\342\224\200", /* ├─ */
867 [DRAW_TREE_RIGHT
] = "\342\224\224\342\224\200", /* └─ */
868 [DRAW_TREE_SPACE
] = " ", /* */
869 [DRAW_TRIANGULAR_BULLET
] = "\342\200\243", /* ‣ */
870 [DRAW_BLACK_CIRCLE
] = "\342\227\217", /* ● */
871 [DRAW_ARROW
] = "\342\206\222", /* → */
872 [DRAW_DASH
] = "\342\200\223", /* – */
875 /* ASCII fallback */ {
876 [DRAW_TREE_VERTICAL
] = "| ",
877 [DRAW_TREE_BRANCH
] = "|-",
878 [DRAW_TREE_RIGHT
] = "`-",
879 [DRAW_TREE_SPACE
] = " ",
880 [DRAW_TRIANGULAR_BULLET
] = ">",
881 [DRAW_BLACK_CIRCLE
] = "*",
887 return draw_table
[!is_locale_utf8()][ch
];
890 int on_ac_power(void) {
891 bool found_offline
= false, found_online
= false;
892 _cleanup_closedir_
DIR *d
= NULL
;
894 d
= opendir("/sys/class/power_supply");
896 return errno
== ENOENT
? true : -errno
;
900 _cleanup_close_
int fd
= -1, device
= -1;
906 if (!de
&& errno
!= 0)
912 if (hidden_file(de
->d_name
))
915 device
= openat(dirfd(d
), de
->d_name
, O_DIRECTORY
|O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
917 if (errno
== ENOENT
|| errno
== ENOTDIR
)
923 fd
= openat(device
, "type", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
931 n
= read(fd
, contents
, sizeof(contents
));
935 if (n
!= 6 || memcmp(contents
, "Mains\n", 6))
939 fd
= openat(device
, "online", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
947 n
= read(fd
, contents
, sizeof(contents
));
951 if (n
!= 2 || contents
[1] != '\n')
954 if (contents
[0] == '1') {
957 } else if (contents
[0] == '0')
958 found_offline
= true;
963 return found_online
|| !found_offline
;
966 void* greedy_realloc(void **p
, size_t *allocated
, size_t need
, size_t size
) {
973 if (*allocated
>= need
)
976 newalloc
= MAX(need
* 2, 64u / size
);
979 /* check for overflows */
988 *allocated
= newalloc
;
992 void* greedy_realloc0(void **p
, size_t *allocated
, size_t need
, size_t size
) {
1001 q
= greedy_realloc(p
, allocated
, need
, size
);
1005 if (*allocated
> prev
)
1006 memzero(q
+ prev
* size
, (*allocated
- prev
) * size
);
1011 bool id128_is_valid(const char *s
) {
1017 /* Simple formatted 128bit hex string */
1019 for (i
= 0; i
< l
; i
++) {
1022 if (!(c
>= '0' && c
<= '9') &&
1023 !(c
>= 'a' && c
<= 'z') &&
1024 !(c
>= 'A' && c
<= 'Z'))
1028 } else if (l
== 36) {
1030 /* Formatted UUID */
1032 for (i
= 0; i
< l
; i
++) {
1035 if ((i
== 8 || i
== 13 || i
== 18 || i
== 23)) {
1039 if (!(c
>= '0' && c
<= '9') &&
1040 !(c
>= 'a' && c
<= 'z') &&
1041 !(c
>= 'A' && c
<= 'Z'))
1052 int shall_restore_state(void) {
1053 _cleanup_free_
char *value
= NULL
;
1056 r
= get_proc_cmdline_key("systemd.restore_state=", &value
);
1062 return parse_boolean(value
) != 0;
1065 int proc_cmdline(char **ret
) {
1068 if (detect_container() > 0)
1069 return get_process_cmdline(1, 0, false, ret
);
1071 return read_one_line_file("/proc/cmdline", ret
);
1074 int parse_proc_cmdline(int (*parse_item
)(const char *key
, const char *value
)) {
1075 _cleanup_free_
char *line
= NULL
;
1081 r
= proc_cmdline(&line
);
1087 _cleanup_free_
char *word
= NULL
;
1090 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_RELAX
);
1096 /* Filter out arguments that are intended only for the
1098 if (!in_initrd() && startswith(word
, "rd."))
1101 value
= strchr(word
, '=');
1105 r
= parse_item(word
, value
);
1113 int get_proc_cmdline_key(const char *key
, char **value
) {
1114 _cleanup_free_
char *line
= NULL
, *ret
= NULL
;
1121 r
= proc_cmdline(&line
);
1127 _cleanup_free_
char *word
= NULL
;
1130 r
= extract_first_word(&p
, &word
, NULL
, EXTRACT_QUOTES
|EXTRACT_RELAX
);
1136 /* Filter out arguments that are intended only for the
1138 if (!in_initrd() && startswith(word
, "rd."))
1142 e
= startswith(word
, key
);
1146 r
= free_and_strdup(&ret
, e
);
1152 if (streq(word
, key
))
1166 int container_get_leader(const char *machine
, pid_t
*pid
) {
1167 _cleanup_free_
char *s
= NULL
, *class = NULL
;
1175 if (!machine_name_is_valid(machine
))
1178 p
= strjoina("/run/systemd/machines/", machine
);
1179 r
= parse_env_file(p
, NEWLINE
, "LEADER", &s
, "CLASS", &class, NULL
);
1187 if (!streq_ptr(class, "container"))
1190 r
= parse_pid(s
, &leader
);
1200 int namespace_open(pid_t pid
, int *pidns_fd
, int *mntns_fd
, int *netns_fd
, int *userns_fd
, int *root_fd
) {
1201 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, netnsfd
= -1, usernsfd
= -1;
1209 mntns
= procfs_file_alloca(pid
, "ns/mnt");
1210 mntnsfd
= open(mntns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
1218 pidns
= procfs_file_alloca(pid
, "ns/pid");
1219 pidnsfd
= open(pidns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
1227 netns
= procfs_file_alloca(pid
, "ns/net");
1228 netnsfd
= open(netns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
1236 userns
= procfs_file_alloca(pid
, "ns/user");
1237 usernsfd
= open(userns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
1238 if (usernsfd
< 0 && errno
!= ENOENT
)
1245 root
= procfs_file_alloca(pid
, "root");
1246 rfd
= open(root
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1252 *pidns_fd
= pidnsfd
;
1255 *mntns_fd
= mntnsfd
;
1258 *netns_fd
= netnsfd
;
1261 *userns_fd
= usernsfd
;
1266 pidnsfd
= mntnsfd
= netnsfd
= usernsfd
= -1;
1271 int namespace_enter(int pidns_fd
, int mntns_fd
, int netns_fd
, int userns_fd
, int root_fd
) {
1272 if (userns_fd
>= 0) {
1273 /* Can't setns to your own userns, since then you could
1274 * escalate from non-root to root in your own namespace, so
1275 * check if namespaces equal before attempting to enter. */
1276 _cleanup_free_
char *userns_fd_path
= NULL
;
1278 if (asprintf(&userns_fd_path
, "/proc/self/fd/%d", userns_fd
) < 0)
1281 r
= files_same(userns_fd_path
, "/proc/self/ns/user");
1289 if (setns(pidns_fd
, CLONE_NEWPID
) < 0)
1293 if (setns(mntns_fd
, CLONE_NEWNS
) < 0)
1297 if (setns(netns_fd
, CLONE_NEWNET
) < 0)
1301 if (setns(userns_fd
, CLONE_NEWUSER
) < 0)
1305 if (fchdir(root_fd
) < 0)
1308 if (chroot(".") < 0)
1312 return reset_uid_gid();
1315 unsigned long personality_from_string(const char *p
) {
1317 /* Parse a personality specifier. We introduce our own
1318 * identifiers that indicate specific ABIs, rather than just
1319 * hints regarding the register size, since we want to keep
1320 * things open for multiple locally supported ABIs for the
1321 * same register size. We try to reuse the ABI identifiers
1322 * used by libseccomp. */
1324 #if defined(__x86_64__)
1326 if (streq(p
, "x86"))
1329 if (streq(p
, "x86-64"))
1332 #elif defined(__i386__)
1334 if (streq(p
, "x86"))
1337 #elif defined(__s390x__)
1339 if (streq(p
, "s390"))
1342 if (streq(p
, "s390x"))
1345 #elif defined(__s390__)
1347 if (streq(p
, "s390"))
1351 return PERSONALITY_INVALID
;
1354 const char* personality_to_string(unsigned long p
) {
1356 #if defined(__x86_64__)
1358 if (p
== PER_LINUX32
)
1364 #elif defined(__i386__)
1369 #elif defined(__s390x__)
1374 if (p
== PER_LINUX32
)
1377 #elif defined(__s390__)
1387 uint64_t physical_memory(void) {
1390 /* We return this as uint64_t in case we are running as 32bit
1391 * process on a 64bit kernel with huge amounts of memory */
1393 mem
= sysconf(_SC_PHYS_PAGES
);
1396 return (uint64_t) mem
* (uint64_t) page_size();
1399 int update_reboot_param_file(const char *param
) {
1403 r
= write_string_file(REBOOT_PARAM_FILE
, param
, WRITE_STRING_FILE_CREATE
);
1405 return log_error_errno(r
, "Failed to write reboot param to "REBOOT_PARAM_FILE
": %m");
1407 (void) unlink(REBOOT_PARAM_FILE
);
1412 int syslog_parse_priority(const char **p
, int *priority
, bool with_facility
) {
1413 int a
= 0, b
= 0, c
= 0;
1423 if (!strchr(*p
, '>'))
1426 if ((*p
)[2] == '>') {
1427 c
= undecchar((*p
)[1]);
1429 } else if ((*p
)[3] == '>') {
1430 b
= undecchar((*p
)[1]);
1431 c
= undecchar((*p
)[2]);
1433 } else if ((*p
)[4] == '>') {
1434 a
= undecchar((*p
)[1]);
1435 b
= undecchar((*p
)[2]);
1436 c
= undecchar((*p
)[3]);
1441 if (a
< 0 || b
< 0 || c
< 0 ||
1442 (!with_facility
&& (a
|| b
|| c
> 7)))
1446 *priority
= a
*100 + b
*10 + c
;
1448 *priority
= (*priority
& LOG_FACMASK
) | c
;
1455 puts(PACKAGE_STRING
"\n"
1460 bool fdname_is_valid(const char *s
) {
1463 /* Validates a name for $LISTEN_FDNAMES. We basically allow
1464 * everything ASCII that's not a control character. Also, as
1465 * special exception the ":" character is not allowed, as we
1466 * use that as field separator in $LISTEN_FDNAMES.
1468 * Note that the empty string is explicitly allowed
1469 * here. However, we limit the length of the names to 255
1475 for (p
= s
; *p
; p
++) {
1487 bool oom_score_adjust_is_valid(int oa
) {
1488 return oa
>= OOM_SCORE_ADJ_MIN
&& oa
<= OOM_SCORE_ADJ_MAX
;