summaryrefslogtreecommitdiff
path: root/src/basic
diff options
context:
space:
mode:
Diffstat (limited to 'src/basic')
-rw-r--r--src/basic/.gitignore16
l---------src/basic/Makefile1
-rw-r--r--src/basic/alloc-util.c27
-rw-r--r--src/basic/alloc-util.h10
-rw-r--r--src/basic/audit-util.c4
-rw-r--r--src/basic/audit-util.h4
-rw-r--r--src/basic/barrier.c2
-rw-r--r--src/basic/barrier.h7
-rw-r--r--src/basic/blkid-util.h4
-rw-r--r--src/basic/bpf-program.c183
-rw-r--r--src/basic/bpf-program.h55
-rw-r--r--src/basic/btrfs-util.c2
-rw-r--r--src/basic/build.h40
-rw-r--r--src/basic/bus-label.h4
-rw-r--r--src/basic/calendarspec.c131
-rw-r--r--src/basic/calendarspec.h1
-rw-r--r--src/basic/cap-list.c67
-rw-r--r--src/basic/cap-list.h3
-rw-r--r--src/basic/capability-util.c104
-rw-r--r--src/basic/capability-util.h2
-rw-r--r--src/basic/cgroup-util.c74
-rw-r--r--src/basic/conf-files.c53
-rw-r--r--src/basic/conf-files.h10
-rw-r--r--src/basic/cpu-set-util.c46
-rw-r--r--src/basic/cpu-set-util.h1
-rw-r--r--src/basic/def.h10
-rw-r--r--src/basic/env-util.c12
-rw-r--r--src/basic/env-util.h1
-rw-r--r--src/basic/escape.c4
-rw-r--r--src/basic/exec-util.c2
-rw-r--r--src/basic/exit-status.c15
-rw-r--r--src/basic/exit-status.h6
-rw-r--r--src/basic/extract-word.c2
-rw-r--r--src/basic/fd-util.c3
-rw-r--r--src/basic/fileio.c191
-rw-r--r--src/basic/fileio.h18
-rw-r--r--src/basic/fs-util.c19
-rw-r--r--src/basic/fs-util.h1
-rw-r--r--src/basic/hashmap.c26
-rw-r--r--src/basic/hashmap.h4
-rw-r--r--src/basic/hexdecoct.c3
-rw-r--r--src/basic/hostname-util.c13
-rw-r--r--src/basic/in-addr-util.c132
-rw-r--r--src/basic/in-addr-util.h17
-rw-r--r--src/basic/io-util.h13
-rw-r--r--src/basic/journal-importer.c9
-rw-r--r--src/basic/log.c225
-rw-r--r--src/basic/log.h20
-rw-r--r--src/basic/memfd-util.c2
-rw-r--r--src/basic/meson.build21
-rw-r--r--src/basic/missing.h103
-rw-r--r--src/basic/missing_syscall.h52
-rw-r--r--src/basic/mkdir.c9
-rw-r--r--src/basic/mount-util.c77
-rw-r--r--src/basic/mount-util.h3
-rw-r--r--src/basic/parse-util.c4
-rw-r--r--src/basic/path-util.c25
-rw-r--r--src/basic/path-util.h12
-rw-r--r--src/basic/process-util.c172
-rw-r--r--src/basic/process-util.h18
-rw-r--r--src/basic/random-util.c10
-rw-r--r--src/basic/replace-var.c2
-rw-r--r--src/basic/replace-var.h2
-rw-r--r--src/basic/rlimit-util.c3
-rw-r--r--src/basic/rm-rf.c6
-rw-r--r--src/basic/securebits-util.c84
-rw-r--r--src/basic/securebits-util.h28
-rw-r--r--src/basic/selinux-util.c34
-rw-r--r--src/basic/set.c61
-rw-r--r--src/basic/set.h2
-rw-r--r--src/basic/signal-util.c2
-rw-r--r--src/basic/smack-util.c2
-rw-r--r--src/basic/socket-label.c2
-rw-r--r--src/basic/socket-util.c22
-rw-r--r--src/basic/socket-util.h20
-rw-r--r--src/basic/special.h1
-rw-r--r--src/basic/string-util.c31
-rw-r--r--src/basic/string-util.h13
-rw-r--r--src/basic/terminal-util.c75
-rw-r--r--src/basic/terminal-util.h25
-rw-r--r--src/basic/time-util.c202
-rw-r--r--src/basic/unit-name.c21
-rw-r--r--src/basic/unit-name.h21
-rw-r--r--src/basic/user-util.c3
-rw-r--r--src/basic/utf8.c2
-rw-r--r--src/basic/util.c135
-rw-r--r--src/basic/util.h3
-rw-r--r--src/basic/virt.c3
-rw-r--r--src/basic/xattr-util.c2
-rw-r--r--src/basic/xml.c2
90 files changed, 2248 insertions, 666 deletions
diff --git a/src/basic/.gitignore b/src/basic/.gitignore
deleted file mode 100644
index e22411e484..0000000000
--- a/src/basic/.gitignore
+++ /dev/null
@@ -1,16 +0,0 @@
-/cap-from-name.gperf
-/cap-from-name.h
-/cap-list.txt
-/cap-to-name.h
-/errno-from-name.gperf
-/errno-from-name.h
-/errno-list.txt
-/errno-to-name.h
-/af-from-name.gperf
-/af-from-name.h
-/af-list.txt
-/af-to-name.h
-/arphrd-from-name.gperf
-/arphrd-from-name.h
-/arphrd-list.txt
-/arphrd-to-name.h
diff --git a/src/basic/Makefile b/src/basic/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/basic/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/basic/alloc-util.c b/src/basic/alloc-util.c
index b540dcddf5..948389f276 100644
--- a/src/basic/alloc-util.c
+++ b/src/basic/alloc-util.c
@@ -25,16 +25,31 @@
#include "util.h"
void* memdup(const void *p, size_t l) {
- void *r;
+ void *ret;
- assert(p);
+ assert(l == 0 || p);
+
+ ret = malloc(l);
+ if (!ret)
+ return NULL;
+
+ memcpy(ret, p, l);
+ return ret;
+}
+
+void* memdup_suffix0(const void*p, size_t l) {
+ void *ret;
+
+ assert(l == 0 || p);
+
+ /* The same as memdup() but place a safety NUL byte after the allocated memory */
- r = malloc(l);
- if (!r)
+ ret = malloc(l + 1);
+ if (!ret)
return NULL;
- memcpy(r, p, l);
- return r;
+ *((uint8_t*) mempcpy(ret, p, l)) = 0;
+ return ret;
}
void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h
index a44dd473c1..0a89691bae 100644
--- a/src/basic/alloc-util.h
+++ b/src/basic/alloc-util.h
@@ -36,6 +36,8 @@
#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
+#define newdup_suffix0(t, p, n) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n)))
+
#define malloc0(n) (calloc(1, (n)))
static inline void *mfree(void *memory) {
@@ -52,6 +54,7 @@ static inline void *mfree(void *memory) {
})
void* memdup(const void *p, size_t l) _alloc_(2);
+void* memdup_suffix0(const void*p, size_t l) _alloc_(2);
static inline void freep(void *p) {
free(*(void**) p);
@@ -84,6 +87,13 @@ _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, si
return memdup(p, size * need);
}
+_alloc_(2, 3) static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) {
+ if (size_multiply_overflow(size, need))
+ return NULL;
+
+ return memdup_suffix0(p, size * need);
+}
+
void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
diff --git a/src/basic/audit-util.c b/src/basic/audit-util.c
index d1c9695973..24a6c8a936 100644
--- a/src/basic/audit-util.c
+++ b/src/basic/audit-util.c
@@ -54,7 +54,7 @@ int audit_session_from_pid(pid_t pid, uint32_t *id) {
if (r < 0)
return r;
- if (u == AUDIT_SESSION_INVALID || u <= 0)
+ if (!audit_session_is_valid(u))
return -ENODATA;
*id = u;
@@ -81,7 +81,7 @@ int audit_loginuid_from_pid(pid_t pid, uid_t *uid) {
if (r < 0)
return r;
- *uid = (uid_t) u;
+ *uid = u;
return 0;
}
diff --git a/src/basic/audit-util.h b/src/basic/audit-util.h
index e048503991..3088951326 100644
--- a/src/basic/audit-util.h
+++ b/src/basic/audit-util.h
@@ -29,3 +29,7 @@ int audit_session_from_pid(pid_t pid, uint32_t *id);
int audit_loginuid_from_pid(pid_t pid, uid_t *uid);
bool use_audit(void);
+
+static inline bool audit_session_is_valid(uint32_t id) {
+ return id > 0 && id != AUDIT_SESSION_INVALID;
+}
diff --git a/src/basic/barrier.c b/src/basic/barrier.c
index 2da633b311..0c44e47b12 100644
--- a/src/basic/barrier.c
+++ b/src/basic/barrier.c
@@ -171,7 +171,7 @@ void barrier_set_role(Barrier *b, unsigned int role) {
int fd;
assert(b);
- assert(role == BARRIER_PARENT || role == BARRIER_CHILD);
+ assert(IN_SET(role, BARRIER_PARENT, BARRIER_CHILD));
/* make sure this is only called once */
assert(b->pipe[0] >= 0 && b->pipe[1] >= 0);
diff --git a/src/basic/barrier.h b/src/basic/barrier.h
index 6347fddc4d..fbc2d9d98d 100644
--- a/src/basic/barrier.h
+++ b/src/basic/barrier.h
@@ -70,11 +70,11 @@ bool barrier_sync_next(Barrier *b);
bool barrier_sync(Barrier *b);
static inline bool barrier_i_aborted(Barrier *b) {
- return b->barriers == BARRIER_I_ABORTED || b->barriers == BARRIER_WE_ABORTED;
+ return IN_SET(b->barriers, BARRIER_I_ABORTED, BARRIER_WE_ABORTED);
}
static inline bool barrier_they_aborted(Barrier *b) {
- return b->barriers == BARRIER_THEY_ABORTED || b->barriers == BARRIER_WE_ABORTED;
+ return IN_SET(b->barriers, BARRIER_THEY_ABORTED, BARRIER_WE_ABORTED);
}
static inline bool barrier_we_aborted(Barrier *b) {
@@ -82,7 +82,8 @@ static inline bool barrier_we_aborted(Barrier *b) {
}
static inline bool barrier_is_aborted(Barrier *b) {
- return b->barriers == BARRIER_I_ABORTED || b->barriers == BARRIER_THEY_ABORTED || b->barriers == BARRIER_WE_ABORTED;
+ return IN_SET(b->barriers,
+ BARRIER_I_ABORTED, BARRIER_THEY_ABORTED, BARRIER_WE_ABORTED);
}
static inline bool barrier_place_and_sync(Barrier *b) {
diff --git a/src/basic/blkid-util.h b/src/basic/blkid-util.h
index 1b9cace040..53340ec6f3 100644
--- a/src/basic/blkid-util.h
+++ b/src/basic/blkid-util.h
@@ -19,13 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#ifdef HAVE_BLKID
+#if HAVE_BLKID
#include <blkid.h>
#endif
#include "util.h"
-#ifdef HAVE_BLKID
+#if HAVE_BLKID
DEFINE_TRIVIAL_CLEANUP_FUNC(blkid_probe, blkid_free_probe);
#define _cleanup_blkid_free_probe_ _cleanup_(blkid_free_probep)
#endif
diff --git a/src/basic/bpf-program.c b/src/basic/bpf-program.c
new file mode 100644
index 0000000000..ce6f9e4409
--- /dev/null
+++ b/src/basic/bpf-program.c
@@ -0,0 +1,183 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Daniel Mack
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "alloc-util.h"
+#include "bpf-program.h"
+#include "fd-util.h"
+#include "log.h"
+#include "missing.h"
+
+int bpf_program_new(uint32_t prog_type, BPFProgram **ret) {
+ _cleanup_(bpf_program_unrefp) BPFProgram *p = NULL;
+
+ p = new0(BPFProgram, 1);
+ if (!p)
+ return log_oom();
+
+ p->prog_type = prog_type;
+ p->kernel_fd = -1;
+
+ *ret = p;
+ p = NULL;
+ return 0;
+}
+
+BPFProgram *bpf_program_unref(BPFProgram *p) {
+ if (!p)
+ return NULL;
+
+ safe_close(p->kernel_fd);
+ free(p->instructions);
+
+ return mfree(p);
+}
+
+int bpf_program_add_instructions(BPFProgram *p, const struct bpf_insn *instructions, size_t count) {
+
+ assert(p);
+
+ if (!GREEDY_REALLOC(p->instructions, p->allocated, p->n_instructions + count))
+ return -ENOMEM;
+
+ memcpy(p->instructions + p->n_instructions, instructions, sizeof(struct bpf_insn) * count);
+ p->n_instructions += count;
+
+ return 0;
+}
+
+int bpf_program_load_kernel(BPFProgram *p, char *log_buf, size_t log_size) {
+ union bpf_attr attr;
+
+ assert(p);
+
+ if (p->kernel_fd >= 0)
+ return -EBUSY;
+
+ attr = (union bpf_attr) {
+ .prog_type = p->prog_type,
+ .insns = PTR_TO_UINT64(p->instructions),
+ .insn_cnt = p->n_instructions,
+ .license = PTR_TO_UINT64("GPL"),
+ .log_buf = PTR_TO_UINT64(log_buf),
+ .log_level = !!log_buf,
+ .log_size = log_size,
+ };
+
+ p->kernel_fd = bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
+ if (p->kernel_fd < 0)
+ return -errno;
+
+ return 0;
+}
+
+int bpf_program_cgroup_attach(BPFProgram *p, int type, const char *path, uint32_t flags) {
+ _cleanup_close_ int fd = -1;
+ union bpf_attr attr;
+
+ assert(p);
+ assert(type >= 0);
+ assert(path);
+
+ fd = open(path, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ attr = (union bpf_attr) {
+ .attach_type = type,
+ .target_fd = fd,
+ .attach_bpf_fd = p->kernel_fd,
+ .attach_flags = flags,
+ };
+
+ if (bpf(BPF_PROG_ATTACH, &attr, sizeof(attr)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int bpf_program_cgroup_detach(int type, const char *path) {
+ _cleanup_close_ int fd = -1;
+ union bpf_attr attr;
+
+ assert(path);
+
+ fd = open(path, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ attr = (union bpf_attr) {
+ .attach_type = type,
+ .target_fd = fd,
+ };
+
+ if (bpf(BPF_PROG_DETACH, &attr, sizeof(attr)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int bpf_map_new(enum bpf_map_type type, size_t key_size, size_t value_size, size_t max_entries, uint32_t flags) {
+ union bpf_attr attr = {
+ .map_type = type,
+ .key_size = key_size,
+ .value_size = value_size,
+ .max_entries = max_entries,
+ .map_flags = flags,
+ };
+ int fd;
+
+ fd = bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
+ if (fd < 0)
+ return -errno;
+
+ return fd;
+}
+
+int bpf_map_update_element(int fd, const void *key, void *value) {
+
+ union bpf_attr attr = {
+ .map_fd = fd,
+ .key = PTR_TO_UINT64(key),
+ .value = PTR_TO_UINT64(value),
+ };
+
+ if (bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int bpf_map_lookup_element(int fd, const void *key, void *value) {
+
+ union bpf_attr attr = {
+ .map_fd = fd,
+ .key = PTR_TO_UINT64(key),
+ .value = PTR_TO_UINT64(value),
+ };
+
+ if (bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr)) < 0)
+ return -errno;
+
+ return 0;
+}
diff --git a/src/basic/bpf-program.h b/src/basic/bpf-program.h
new file mode 100644
index 0000000000..35a41ffc44
--- /dev/null
+++ b/src/basic/bpf-program.h
@@ -0,0 +1,55 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Daniel Mack
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+
+ [Except for the stuff copy/pasted from the kernel sources, see below]
+***/
+
+#include <linux/bpf.h>
+#include <stdint.h>
+#include <sys/syscall.h>
+
+#include "list.h"
+#include "macro.h"
+
+typedef struct BPFProgram BPFProgram;
+
+struct BPFProgram {
+ int kernel_fd;
+ uint32_t prog_type;
+
+ size_t n_instructions;
+ size_t allocated;
+ struct bpf_insn *instructions;
+};
+
+int bpf_program_new(uint32_t prog_type, BPFProgram **ret);
+BPFProgram *bpf_program_unref(BPFProgram *p);
+
+int bpf_program_add_instructions(BPFProgram *p, const struct bpf_insn *insn, size_t count);
+int bpf_program_load_kernel(BPFProgram *p, char *log_buf, size_t log_size);
+
+int bpf_program_cgroup_attach(BPFProgram *p, int type, const char *path, uint32_t flags);
+int bpf_program_cgroup_detach(int type, const char *path);
+
+int bpf_map_new(enum bpf_map_type type, size_t key_size, size_t value_size, size_t max_entries, uint32_t flags);
+int bpf_map_update_element(int fd, const void *key, void *value);
+int bpf_map_lookup_element(int fd, const void *key, void *value);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(BPFProgram*, bpf_program_unref);
diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c
index 5505499312..c2061addd1 100644
--- a/src/basic/btrfs-util.c
+++ b/src/basic/btrfs-util.c
@@ -32,7 +32,7 @@
#include <sys/sysmacros.h>
#include <unistd.h>
-#ifdef HAVE_LINUX_BTRFS_H
+#if HAVE_LINUX_BTRFS_H
#include <linux/btrfs.h>
#endif
diff --git a/src/basic/build.h b/src/basic/build.h
index 3223915da6..9aaa6e3dae 100644
--- a/src/basic/build.h
+++ b/src/basic/build.h
@@ -19,121 +19,121 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#ifdef HAVE_PAM
+#if HAVE_PAM
#define _PAM_FEATURE_ "+PAM"
#else
#define _PAM_FEATURE_ "-PAM"
#endif
-#ifdef HAVE_AUDIT
+#if HAVE_AUDIT
#define _AUDIT_FEATURE_ "+AUDIT"
#else
#define _AUDIT_FEATURE_ "-AUDIT"
#endif
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
#define _SELINUX_FEATURE_ "+SELINUX"
#else
#define _SELINUX_FEATURE_ "-SELINUX"
#endif
-#ifdef HAVE_APPARMOR
+#if HAVE_APPARMOR
#define _APPARMOR_FEATURE_ "+APPARMOR"
#else
#define _APPARMOR_FEATURE_ "-APPARMOR"
#endif
-#ifdef HAVE_IMA
+#if ENABLE_IMA
#define _IMA_FEATURE_ "+IMA"
#else
#define _IMA_FEATURE_ "-IMA"
#endif
-#ifdef HAVE_SMACK
+#if ENABLE_SMACK
#define _SMACK_FEATURE_ "+SMACK"
#else
#define _SMACK_FEATURE_ "-SMACK"
#endif
-#ifdef HAVE_SYSV_COMPAT
+#if HAVE_SYSV_COMPAT
#define _SYSVINIT_FEATURE_ "+SYSVINIT"
#else
#define _SYSVINIT_FEATURE_ "-SYSVINIT"
#endif
-#ifdef HAVE_UTMP
+#if ENABLE_UTMP
#define _UTMP_FEATURE_ "+UTMP"
#else
#define _UTMP_FEATURE_ "-UTMP"
#endif
-#ifdef HAVE_LIBCRYPTSETUP
+#if HAVE_LIBCRYPTSETUP
#define _LIBCRYPTSETUP_FEATURE_ "+LIBCRYPTSETUP"
#else
#define _LIBCRYPTSETUP_FEATURE_ "-LIBCRYPTSETUP"
#endif
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
#define _GCRYPT_FEATURE_ "+GCRYPT"
#else
#define _GCRYPT_FEATURE_ "-GCRYPT"
#endif
-#ifdef HAVE_GNUTLS
+#if HAVE_GNUTLS
#define _GNUTLS_FEATURE_ "+GNUTLS"
#else
#define _GNUTLS_FEATURE_ "-GNUTLS"
#endif
-#ifdef HAVE_ACL
+#if HAVE_ACL
#define _ACL_FEATURE_ "+ACL"
#else
#define _ACL_FEATURE_ "-ACL"
#endif
-#ifdef HAVE_XZ
+#if HAVE_XZ
#define _XZ_FEATURE_ "+XZ"
#else
#define _XZ_FEATURE_ "-XZ"
#endif
-#ifdef HAVE_LZ4
+#if HAVE_LZ4
#define _LZ4_FEATURE_ "+LZ4"
#else
#define _LZ4_FEATURE_ "-LZ4"
#endif
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
#define _SECCOMP_FEATURE_ "+SECCOMP"
#else
#define _SECCOMP_FEATURE_ "-SECCOMP"
#endif
-#ifdef HAVE_BLKID
+#if HAVE_BLKID
#define _BLKID_FEATURE_ "+BLKID"
#else
#define _BLKID_FEATURE_ "-BLKID"
#endif
-#ifdef HAVE_ELFUTILS
+#if HAVE_ELFUTILS
#define _ELFUTILS_FEATURE_ "+ELFUTILS"
#else
#define _ELFUTILS_FEATURE_ "-ELFUTILS"
#endif
-#ifdef HAVE_KMOD
+#if HAVE_KMOD
#define _KMOD_FEATURE_ "+KMOD"
#else
#define _KMOD_FEATURE_ "-KMOD"
#endif
-#ifdef HAVE_LIBIDN2
+#if HAVE_LIBIDN2
#define _IDN2_FEATURE_ "+IDN2"
#else
#define _IDN2_FEATURE_ "-IDN2"
#endif
-#ifdef HAVE_LIBIDN
+#if HAVE_LIBIDN
#define _IDN_FEATURE_ "+IDN"
#else
#define _IDN_FEATURE_ "-IDN"
diff --git a/src/basic/bus-label.h b/src/basic/bus-label.h
index 62fb2c450c..600268b767 100644
--- a/src/basic/bus-label.h
+++ b/src/basic/bus-label.h
@@ -23,9 +23,11 @@
#include <stdlib.h>
#include <string.h>
+#include "string-util.h"
+
char *bus_label_escape(const char *s);
char *bus_label_unescape_n(const char *f, size_t l);
static inline char *bus_label_unescape(const char *f) {
- return bus_label_unescape_n(f, f ? strlen(f) : 0);
+ return bus_label_unescape_n(f, strlen_ptr(f));
}
diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c
index 204120ee0e..1fc9e9b154 100644
--- a/src/basic/calendarspec.c
+++ b/src/basic/calendarspec.c
@@ -25,6 +25,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/mman.h>
#include <time.h>
#include "alloc-util.h"
@@ -33,6 +34,7 @@
#include "macro.h"
#include "parse-util.h"
#include "string-util.h"
+#include "time-util.h"
#define BITS_WEEKDAYS 127
#define MIN_YEAR 1970
@@ -59,6 +61,7 @@ void calendar_spec_free(CalendarSpec *c) {
free_chain(c->hour);
free_chain(c->minute);
free_chain(c->microsecond);
+ free(c->timezone);
free(c);
}
@@ -257,19 +260,19 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) {
if (l < 0) {
if (need_comma)
- fputc(',', f);
+ fputc_unlocked(',', f);
else
need_comma = true;
- fputs(days[x], f);
+ fputs_unlocked(days[x], f);
l = x;
}
} else if (l >= 0) {
if (x > l + 1) {
- fputs(x > l + 2 ? ".." : ",", f);
- fputs(days[x-1], f);
+ fputs_unlocked(x > l + 2 ? ".." : ",", f);
+ fputs_unlocked(days[x-1], f);
}
l = -1;
@@ -277,8 +280,8 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) {
}
if (l >= 0 && x > l + 1) {
- fputs(x > l + 2 ? ".." : ",", f);
- fputs(days[x-1], f);
+ fputs_unlocked(x > l + 2 ? ".." : ",", f);
+ fputs_unlocked(days[x-1], f);
}
}
@@ -288,12 +291,12 @@ static void format_chain(FILE *f, int space, const CalendarComponent *c, bool us
assert(f);
if (!c) {
- fputc('*', f);
+ fputc_unlocked('*', f);
return;
}
if (usec && c->start == 0 && c->repeat == USEC_PER_SEC && !c->next) {
- fputc('*', f);
+ fputc_unlocked('*', f);
return;
}
@@ -314,7 +317,7 @@ static void format_chain(FILE *f, int space, const CalendarComponent *c, bool us
fprintf(f, ".%06i", c->repeat % d);
if (c->next) {
- fputc(',', f);
+ fputc_unlocked(',', f);
format_chain(f, space, c->next, usec);
}
}
@@ -334,32 +337,35 @@ int calendar_spec_to_string(const CalendarSpec *c, char **p) {
if (c->weekdays_bits > 0 && c->weekdays_bits <= BITS_WEEKDAYS) {
format_weekdays(f, c);
- fputc(' ', f);
+ fputc_unlocked(' ', f);
}
format_chain(f, 4, c->year, false);
- fputc('-', f);
+ fputc_unlocked('-', f);
format_chain(f, 2, c->month, false);
- fputc(c->end_of_month ? '~' : '-', f);
+ fputc_unlocked(c->end_of_month ? '~' : '-', f);
format_chain(f, 2, c->day, false);
- fputc(' ', f);
+ fputc_unlocked(' ', f);
format_chain(f, 2, c->hour, false);
- fputc(':', f);
+ fputc_unlocked(':', f);
format_chain(f, 2, c->minute, false);
- fputc(':', f);
+ fputc_unlocked(':', f);
format_chain(f, 2, c->microsecond, true);
if (c->utc)
- fputs(" UTC", f);
- else if (IN_SET(c->dst, 0, 1)) {
+ fputs_unlocked(" UTC", f);
+ else if (c->timezone != NULL) {
+ fputc_unlocked(' ', f);
+ fputs_unlocked(c->timezone, f);
+ } else if (IN_SET(c->dst, 0, 1)) {
/* If daylight saving is explicitly on or off, let's show the used timezone. */
tzset();
if (!isempty(tzname[c->dst])) {
- fputc(' ', f);
- fputs(tzname[c->dst], f);
+ fputc_unlocked(' ', f);
+ fputs_unlocked(tzname[c->dst], f);
}
}
@@ -415,11 +421,7 @@ static int parse_weekdays(const char **p, CalendarSpec *c) {
skip = strlen(day_nr[i].name);
- if ((*p)[skip] != '-' &&
- (*p)[skip] != '.' &&
- (*p)[skip] != ',' &&
- (*p)[skip] != ' ' &&
- (*p)[skip] != 0)
+ if (!IN_SET((*p)[skip], 0, '-', '.', ',', ' '))
return -EINVAL;
c->weekdays_bits |= 1 << day_nr[i].nr;
@@ -478,7 +480,7 @@ static int parse_weekdays(const char **p, CalendarSpec *c) {
}
/* Allow a trailing comma but not an open range */
- if (**p == 0 || **p == ' ') {
+ if (IN_SET(**p, 0, ' ')) {
*p += strspn(*p, " ");
return l < 0 ? 0 : -EINVAL;
}
@@ -638,7 +640,7 @@ static int prepend_component(const char **p, bool usec, CalendarComponent **c) {
return -ERANGE;
}
- if (*e != 0 && *e != ' ' && *e != ',' && *e != '-' && *e != '~' && *e != ':')
+ if (!IN_SET(*e, 0, ' ', ',', '-', '~', ':'))
return -EINVAL;
cc = new0(CalendarComponent, 1);
@@ -735,7 +737,7 @@ static int parse_date(const char **p, CalendarSpec *c) {
return r;
/* Already the end? A ':' as separator? In that case this was a time, not a date */
- if (*t == 0 || *t == ':') {
+ if (IN_SET(*t, 0, ':')) {
free_chain(first);
return 0;
}
@@ -755,7 +757,7 @@ static int parse_date(const char **p, CalendarSpec *c) {
}
/* Got two parts, hence it's month and day */
- if (*t == ' ' || *t == 0) {
+ if (IN_SET(*t, 0, ' ')) {
*p = t + strspn(t, " ");
c->month = first;
c->day = second;
@@ -783,7 +785,7 @@ static int parse_date(const char **p, CalendarSpec *c) {
}
/* Got three parts, hence it is year, month and day */
- if (*t == ' ' || *t == 0) {
+ if (IN_SET(*t, 0, ' ')) {
*p = t + strspn(t, " ");
c->year = first;
c->month = second;
@@ -888,6 +890,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
if (!c)
return -ENOMEM;
c->dst = -1;
+ c->timezone = NULL;
utc = endswith_no_case(p, " UTC");
if (utc) {
@@ -919,6 +922,19 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
if (IN_SET(j, 0, 1)) {
p = strndupa(p, e - p - 1);
c->dst = j;
+ } else {
+ const char *last_space;
+
+ last_space = strrchr(p, ' ');
+ if (last_space != NULL && timezone_is_valid(last_space + 1)) {
+ c->timezone = strdup(last_space + 1);
+ if (!c->timezone) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ p = strndupa(p, last_space - p);
+ }
}
}
@@ -1293,7 +1309,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) {
}
}
-int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next) {
+static int calendar_spec_next_usec_impl(const CalendarSpec *spec, usec_t usec, usec_t *next) {
struct tm tm;
time_t t;
int r;
@@ -1321,3 +1337,58 @@ int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next)
*next = (usec_t) t * USEC_PER_SEC + tm_usec;
return 0;
}
+
+typedef struct SpecNextResult {
+ usec_t next;
+ int return_value;
+} SpecNextResult;
+
+int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next) {
+ pid_t pid;
+ SpecNextResult *shared;
+ SpecNextResult tmp;
+ int r;
+
+ if (isempty(spec->timezone))
+ return calendar_spec_next_usec_impl(spec, usec, next);
+
+ shared = mmap(NULL, sizeof *shared, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
+ if (shared == MAP_FAILED)
+ return negative_errno();
+
+ pid = fork();
+
+ if (pid == -1) {
+ int fork_errno = errno;
+ (void) munmap(shared, sizeof *shared);
+ return -fork_errno;
+ }
+
+ if (pid == 0) {
+ if (setenv("TZ", spec->timezone, 1) != 0) {
+ shared->return_value = negative_errno();
+ _exit(EXIT_FAILURE);
+ }
+
+ tzset();
+
+ shared->return_value = calendar_spec_next_usec_impl(spec, usec, &shared->next);
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ r = wait_for_terminate(pid, NULL);
+ if (r < 0) {
+ (void) munmap(shared, sizeof *shared);
+ return r;
+ }
+
+ tmp = *shared;
+ if (munmap(shared, sizeof *shared) != 0)
+ return negative_errno();
+
+ if (tmp.return_value == 0)
+ *next = tmp.next;
+
+ return tmp.return_value;
+}
diff --git a/src/basic/calendarspec.h b/src/basic/calendarspec.h
index 3d8798de0b..8888251705 100644
--- a/src/basic/calendarspec.h
+++ b/src/basic/calendarspec.h
@@ -40,6 +40,7 @@ typedef struct CalendarSpec {
bool end_of_month;
bool utc;
int dst;
+ char *timezone;
CalendarComponent *year;
CalendarComponent *month;
diff --git a/src/basic/cap-list.c b/src/basic/cap-list.c
index d68cc78d05..2e9b2d9a55 100644
--- a/src/basic/cap-list.c
+++ b/src/basic/cap-list.c
@@ -20,7 +20,10 @@
#include <errno.h>
#include <string.h>
+#include "alloc-util.h"
+#include "capability-util.h"
#include "cap-list.h"
+#include "extract-word.h"
#include "macro.h"
#include "missing.h"
#include "parse-util.h"
@@ -64,3 +67,67 @@ int capability_from_name(const char *name) {
int capability_list_length(void) {
return (int) ELEMENTSOF(capability_names);
}
+
+int capability_set_to_string_alloc(uint64_t set, char **s) {
+ _cleanup_free_ char *str = NULL;
+ unsigned long i;
+ size_t allocated = 0, n = 0;
+
+ assert(s);
+
+ for (i = 0; i < cap_last_cap(); i++)
+ if (set & (UINT64_C(1) << i)) {
+ const char *p;
+ size_t add;
+
+ p = capability_to_name(i);
+ if (!p)
+ return -EINVAL;
+
+ add = strlen(p);
+
+ if (!GREEDY_REALLOC(str, allocated, n + add + 2))
+ return -ENOMEM;
+
+ strcpy(mempcpy(str + n, p, add), " ");
+ n += add + 1;
+ }
+
+ if (!GREEDY_REALLOC(str, allocated, n + 1))
+ return -ENOMEM;
+
+ str[n > 0 ? n - 1 : 0] = '\0'; /* truncate the last space, if it's there */
+
+ *s = str;
+ str = NULL;
+
+ return 0;
+}
+
+int capability_set_from_string(const char *s, uint64_t *set) {
+ uint64_t val = 0;
+ const char *p;
+
+ assert(set);
+
+ for (p = s;;) {
+ _cleanup_free_ char *word = NULL;
+ int r;
+
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+ if (r == -ENOMEM)
+ return r;
+ if (r <= 0)
+ break;
+
+ r = capability_from_name(word);
+ if (r < 0)
+ continue;
+
+ val |= ((uint64_t) UINT64_C(1)) << (uint64_t) r;
+ }
+
+ *set = val;
+
+ return 0;
+}
diff --git a/src/basic/cap-list.h b/src/basic/cap-list.h
index c1f6b94ad3..f9f6b70d80 100644
--- a/src/basic/cap-list.h
+++ b/src/basic/cap-list.h
@@ -22,3 +22,6 @@
const char *capability_to_name(int id);
int capability_from_name(const char *name);
int capability_list_length(void);
+
+int capability_set_to_string_alloc(uint64_t set, char **s);
+int capability_set_from_string(const char *s, uint64_t *set);
diff --git a/src/basic/capability-util.c b/src/basic/capability-util.c
index c3de20a0e8..96c2e992bd 100644
--- a/src/basic/capability-util.c
+++ b/src/basic/capability-util.c
@@ -151,7 +151,7 @@ int capability_ambient_set_apply(uint64_t set, bool also_inherit) {
}
int capability_bounding_set_drop(uint64_t keep, bool right_now) {
- _cleanup_cap_free_ cap_t after_cap = NULL;
+ _cleanup_cap_free_ cap_t before_cap = NULL, after_cap = NULL;
cap_flag_value_t fv;
unsigned long i;
int r;
@@ -161,71 +161,80 @@ int capability_bounding_set_drop(uint64_t keep, bool right_now) {
* executing init!), so get it back temporarily so that we can
* call PR_CAPBSET_DROP. */
- after_cap = cap_get_proc();
- if (!after_cap)
+ before_cap = cap_get_proc();
+ if (!before_cap)
return -errno;
- if (cap_get_flag(after_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0)
+ if (cap_get_flag(before_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0)
return -errno;
if (fv != CAP_SET) {
_cleanup_cap_free_ cap_t temp_cap = NULL;
static const cap_value_t v = CAP_SETPCAP;
- temp_cap = cap_dup(after_cap);
- if (!temp_cap) {
- r = -errno;
- goto finish;
- }
+ temp_cap = cap_dup(before_cap);
+ if (!temp_cap)
+ return -errno;
- if (cap_set_flag(temp_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0) {
- r = -errno;
- goto finish;
- }
+ if (cap_set_flag(temp_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0)
+ return -errno;
- if (cap_set_proc(temp_cap) < 0) {
- r = -errno;
- goto finish;
- }
+ if (cap_set_proc(temp_cap) < 0)
+ log_debug_errno(errno, "Can't acquire effective CAP_SETPCAP bit, ignoring: %m");
+
+ /* If we didn't manage to acquire the CAP_SETPCAP bit, we continue anyway, after all this just means
+ * we'll fail later, when we actually intend to drop some capabilities. */
}
+ after_cap = cap_dup(before_cap);
+ if (!after_cap)
+ return -errno;
+
for (i = 0; i <= cap_last_cap(); i++) {
+ cap_value_t v;
- if (!(keep & (UINT64_C(1) << i))) {
- cap_value_t v;
+ if ((keep & (UINT64_C(1) << i)))
+ continue;
- /* Drop it from the bounding set */
- if (prctl(PR_CAPBSET_DROP, i) < 0) {
- r = -errno;
+ /* Drop it from the bounding set */
+ if (prctl(PR_CAPBSET_DROP, i) < 0) {
+ r = -errno;
+
+ /* If dropping the capability failed, let's see if we didn't have it in the first place. If so,
+ * continue anyway, as dropping a capability we didn't have in the first place doesn't really
+ * matter anyway. */
+ if (prctl(PR_CAPBSET_READ, i) != 0)
goto finish;
- }
- v = (cap_value_t) i;
+ }
+ v = (cap_value_t) i;
+
+ /* Also drop it from the inheritable set, so
+ * that anything we exec() loses the
+ * capability for good. */
+ if (cap_set_flag(after_cap, CAP_INHERITABLE, 1, &v, CAP_CLEAR) < 0) {
+ r = -errno;
+ goto finish;
+ }
- /* Also drop it from the inheritable set, so
- * that anything we exec() loses the
- * capability for good. */
- if (cap_set_flag(after_cap, CAP_INHERITABLE, 1, &v, CAP_CLEAR) < 0) {
+ /* If we shall apply this right now drop it
+ * also from our own capability sets. */
+ if (right_now) {
+ if (cap_set_flag(after_cap, CAP_PERMITTED, 1, &v, CAP_CLEAR) < 0 ||
+ cap_set_flag(after_cap, CAP_EFFECTIVE, 1, &v, CAP_CLEAR) < 0) {
r = -errno;
goto finish;
}
-
- /* If we shall apply this right now drop it
- * also from our own capability sets. */
- if (right_now) {
- if (cap_set_flag(after_cap, CAP_PERMITTED, 1, &v, CAP_CLEAR) < 0 ||
- cap_set_flag(after_cap, CAP_EFFECTIVE, 1, &v, CAP_CLEAR) < 0) {
- r = -errno;
- goto finish;
- }
- }
}
}
r = 0;
finish:
- if (cap_set_proc(after_cap) < 0)
- return -errno;
+ if (cap_set_proc(after_cap) < 0) {
+ /* If there are no actual changes anyway then let's ignore this error. */
+ if (cap_compare(before_cap, after_cap) != 0)
+ r = -errno;
+ }
return r;
}
@@ -361,3 +370,18 @@ int drop_capability(cap_value_t cv) {
return 0;
}
+
+bool ambient_capabilities_supported(void) {
+ static int cache = -1;
+
+ if (cache >= 0)
+ return cache;
+
+ /* If PR_CAP_AMBIENT returns something valid, or an unexpected error code we assume that ambient caps are
+ * available. */
+
+ cache = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_KILL, 0, 0) >= 0 ||
+ !IN_SET(errno, EINVAL, EOPNOTSUPP, ENOSYS);
+
+ return cache;
+}
diff --git a/src/basic/capability-util.h b/src/basic/capability-util.h
index 35a896e229..3dc9429153 100644
--- a/src/basic/capability-util.h
+++ b/src/basic/capability-util.h
@@ -55,3 +55,5 @@ static inline bool cap_test_all(uint64_t caps) {
m = (UINT64_C(1) << (cap_last_cap() + 1)) - 1;
return (caps & m) == m;
}
+
+bool ambient_capabilities_supported(void);
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index 6344372610..d51c3efd22 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -103,9 +103,12 @@ int cg_read_pid(FILE *f, pid_t *_pid) {
return 1;
}
-int cg_read_event(const char *controller, const char *path, const char *event,
- char **val)
-{
+int cg_read_event(
+ const char *controller,
+ const char *path,
+ const char *event,
+ char **val) {
+
_cleanup_free_ char *events = NULL, *content = NULL;
char *p, *line;
int r;
@@ -255,7 +258,7 @@ int cg_kill(
return -ENOMEM;
}
- my_pid = getpid();
+ my_pid = getpid_cached();
do {
_cleanup_fclose_ FILE *f = NULL;
@@ -371,7 +374,7 @@ int cg_kill_recursive(
if (flags & CGROUP_REMOVE) {
r = cg_rmdir(controller, path);
- if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
+ if (r < 0 && ret >= 0 && !IN_SET(r, -ENOENT, -EBUSY))
return r;
}
@@ -399,7 +402,7 @@ int cg_migrate(
if (!s)
return -ENOMEM;
- my_pid = getpid();
+ my_pid = getpid_cached();
do {
_cleanup_fclose_ FILE *f = NULL;
@@ -506,7 +509,7 @@ int cg_migrate_recursive(
if (flags & CGROUP_REMOVE) {
r = cg_rmdir(cfrom, pfrom);
- if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
+ if (r < 0 && ret >= 0 && !IN_SET(r, -ENOENT, -EBUSY))
return r;
}
@@ -825,7 +828,7 @@ int cg_attach(const char *controller, const char *path, pid_t pid) {
return r;
if (pid == 0)
- pid = getpid();
+ pid = getpid_cached();
xsprintf(c, PID_FMT "\n", pid);
@@ -902,7 +905,7 @@ int cg_set_group_access(
if (r > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
r = cg_set_group_access(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, mode, uid, gid);
if (r < 0)
- log_warning_errno(r, "Failed to set group access on compat systemd cgroup %s: %m", path);
+ log_debug_errno(r, "Failed to set group access on compatibility systemd cgroup %s, ignoring: %m", path);
}
return 0;
@@ -915,7 +918,7 @@ int cg_set_task_access(
uid_t uid,
gid_t gid) {
- _cleanup_free_ char *fs = NULL, *procs = NULL;
+ _cleanup_free_ char *fs = NULL;
int r;
assert(path);
@@ -926,6 +929,7 @@ int cg_set_task_access(
if (mode != MODE_INVALID)
mode &= 0666;
+ /* For both the legacy and unified hierarchies, "cgroup.procs" is the main entry point for PIDs */
r = cg_get_path(controller, path, "cgroup.procs", &fs);
if (r < 0)
return r;
@@ -938,19 +942,48 @@ int cg_set_task_access(
if (r < 0)
return r;
if (r == 0) {
- /* Compatibility, Always keep values for "tasks" in sync with
- * "cgroup.procs" */
- if (cg_get_path(controller, path, "tasks", &procs) >= 0)
- (void) chmod_and_chown(procs, mode, uid, gid);
+ const char *fn;
+
+ /* Compatibility: on cgroupsv1 always keep values for the legacy files "tasks" and
+ * "cgroup.clone_children" in sync with "cgroup.procs". Since this is legacy stuff, we don't care if
+ * this fails. */
+
+ FOREACH_STRING(fn,
+ "tasks",
+ "cgroup.clone_children") {
+
+ fs = mfree(fs);
+
+ r = cg_get_path(controller, path, fn, &fs);
+ if (r < 0)
+ log_debug_errno(r, "Failed to get path for %s of %s, ignoring: %m", fn, path);
+
+ r = chmod_and_chown(fs, mode, uid, gid);
+ if (r < 0)
+ log_debug_errno(r, "Failed to to change ownership/access mode for %s of %s, ignoring: %m", fn, path);
+ }
+ } else {
+ /* On the unified controller, we want to permit subtree controllers too. */
+
+ fs = mfree(fs);
+ r = cg_get_path(controller, path, "cgroup.subtree_control", &fs);
+ if (r < 0)
+ return r;
+
+ r = chmod_and_chown(fs, mode, uid, gid);
+ if (r < 0)
+ return r;
}
r = cg_hybrid_unified();
if (r < 0)
return r;
if (r > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
+ /* Always propagate access mode from unified to legacy controller */
+
r = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, mode, uid, gid);
if (r < 0)
- log_warning_errno(r, "Failed to set task access on compat systemd cgroup %s: %m", path);
+ log_debug_errno(r, "Failed to set task access on compatibility systemd cgroup %s, ignoring: %m", path);
}
return 0;
@@ -1850,9 +1883,7 @@ char *cg_escape(const char *p) {
/* The return value of this function (unlike cg_unescape())
* needs free()! */
- if (p[0] == 0 ||
- p[0] == '_' ||
- p[0] == '.' ||
+ if (IN_SET(p[0], 0, '_', '.') ||
streq(p, "notify_on_release") ||
streq(p, "release_agent") ||
streq(p, "tasks") ||
@@ -1918,7 +1949,7 @@ bool cg_controller_is_valid(const char *p) {
if (s)
p = s;
- if (*p == 0 || *p == '_')
+ if (IN_SET(*p, 0, '_'))
return false;
for (t = p; *t; t++)
@@ -1970,7 +2001,7 @@ int cg_slice_to_path(const char *unit, char **ret) {
char n[dash - p + sizeof(".slice")];
/* Don't allow trailing or double dashes */
- if (dash[1] == 0 || dash[1] == '-')
+ if (IN_SET(dash[1], 0, '-'))
return -EINVAL;
strcpy(stpncpy(n, p, dash - p), ".slice");
@@ -2326,7 +2357,6 @@ int cg_mask_supported(CGroupMask *ret) {
int cg_kernel_controllers(Set *controllers) {
_cleanup_fclose_ FILE *f = NULL;
- char buf[LINE_MAX];
int r;
assert(controllers);
@@ -2344,7 +2374,7 @@ int cg_kernel_controllers(Set *controllers) {
}
/* Ignore the header line */
- (void) fgets(buf, sizeof(buf), f);
+ (void) read_line(f, (size_t) -1, NULL);
for (;;) {
char *controller;
diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c
index b8f0f5d03d..907d1350fe 100644
--- a/src/basic/conf-files.c
+++ b/src/basic/conf-files.c
@@ -32,11 +32,12 @@
#include "macro.h"
#include "missing.h"
#include "path-util.h"
+#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
#include "util.h"
-static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) {
+static int files_add(Hashmap *h, const char *suffix, const char *root, unsigned flags, const char *path) {
_cleanup_closedir_ DIR *dir = NULL;
const char *dirpath;
struct dirent *de;
@@ -56,8 +57,40 @@ static int files_add(Hashmap *h, const char *root, const char *path, const char
FOREACH_DIRENT(de, dir, return -errno) {
char *p;
- if (!dirent_is_file_with_suffix(de, suffix))
+ if (!dirent_is_file_with_suffix(de, suffix)) {
+ log_debug("Ignoring %s/%s, because it's not a regular file with suffix %s.", dirpath, de->d_name, strna(suffix));
continue;
+ }
+
+ if (flags & CONF_FILES_EXECUTABLE) {
+ struct stat st;
+
+ /* As requested: check if the file is marked exectuable. Note that we don't check access(X_OK)
+ * here, as we care about whether the file is marked executable at all, and not whether it is
+ * executable for us, because if such errors are stuff we should log about. */
+
+ if (fstatat(dirfd(dir), de->d_name, &st, 0) < 0) {
+ log_debug_errno(errno, "Failed to stat %s/%s, ignoring: %m", dirpath, de->d_name);
+ continue;
+ }
+
+ if (!null_or_empty(&st)) {
+ /* A mask is a symlink to /dev/null or an empty file. It does not even
+ * have to be executable. Other entries must be regular executable files
+ * or symlinks to them. */
+ if (S_ISREG(st.st_mode)) {
+ if ((st.st_mode & 0111) == 0) { /* not executable */
+ log_debug("Ignoring %s/%s, as it is not marked executable.",
+ dirpath, de->d_name);
+ continue;
+ }
+ } else {
+ log_debug("Ignoring %s/%s, as it is neither a regular file nor a mask.",
+ dirpath, de->d_name);
+ continue;
+ }
+ }
+ }
p = strjoin(dirpath, "/", de->d_name);
if (!p)
@@ -87,7 +120,7 @@ static int base_cmp(const void *a, const void *b) {
return strcmp(basename(s1), basename(s2));
}
-static int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, char **dirs) {
+static int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, unsigned flags, char **dirs) {
_cleanup_hashmap_free_ Hashmap *fh = NULL;
char **files, **p;
int r;
@@ -103,7 +136,7 @@ static int conf_files_list_strv_internal(char ***strv, const char *suffix, const
return -ENOMEM;
STRV_FOREACH(p, dirs) {
- r = files_add(fh, root, *p, suffix);
+ r = files_add(fh, suffix, root, flags, *p);
if (r == -ENOMEM)
return r;
if (r < 0)
@@ -120,7 +153,7 @@ static int conf_files_list_strv_internal(char ***strv, const char *suffix, const
return 0;
}
-int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char* const* dirs) {
+int conf_files_list_strv(char ***strv, const char *suffix, const char *root, unsigned flags, const char* const* dirs) {
_cleanup_strv_free_ char **copy = NULL;
assert(strv);
@@ -129,10 +162,10 @@ int conf_files_list_strv(char ***strv, const char *suffix, const char *root, con
if (!copy)
return -ENOMEM;
- return conf_files_list_strv_internal(strv, suffix, root, copy);
+ return conf_files_list_strv_internal(strv, suffix, root, flags, copy);
}
-int conf_files_list(char ***strv, const char *suffix, const char *root, const char *dir, ...) {
+int conf_files_list(char ***strv, const char *suffix, const char *root, unsigned flags, const char *dir, ...) {
_cleanup_strv_free_ char **dirs = NULL;
va_list ap;
@@ -145,10 +178,10 @@ int conf_files_list(char ***strv, const char *suffix, const char *root, const ch
if (!dirs)
return -ENOMEM;
- return conf_files_list_strv_internal(strv, suffix, root, dirs);
+ return conf_files_list_strv_internal(strv, suffix, root, flags, dirs);
}
-int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, const char *d) {
+int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, unsigned flags, const char *d) {
_cleanup_strv_free_ char **dirs = NULL;
assert(strv);
@@ -157,5 +190,5 @@ int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, c
if (!dirs)
return -ENOMEM;
- return conf_files_list_strv_internal(strv, suffix, root, dirs);
+ return conf_files_list_strv_internal(strv, suffix, root, flags, dirs);
}
diff --git a/src/basic/conf-files.h b/src/basic/conf-files.h
index e00e0e81fb..20ecf6e5f1 100644
--- a/src/basic/conf-files.h
+++ b/src/basic/conf-files.h
@@ -20,6 +20,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-int conf_files_list(char ***ret, const char *suffix, const char *root, const char *dir, ...);
-int conf_files_list_strv(char ***ret, const char *suffix, const char *root, const char* const* dirs);
-int conf_files_list_nulstr(char ***ret, const char *suffix, const char *root, const char *dirs);
+enum {
+ CONF_FILES_EXECUTABLE = 1,
+};
+
+int conf_files_list(char ***ret, const char *suffix, const char *root, unsigned flags, const char *dir, ...);
+int conf_files_list_strv(char ***ret, const char *suffix, const char *root, unsigned flags, const char* const* dirs);
+int conf_files_list_nulstr(char ***ret, const char *suffix, const char *root, unsigned flags, const char *dirs);
diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c
index 95ed6928ff..aec0edc3dc 100644
--- a/src/basic/cpu-set-util.c
+++ b/src/basic/cpu-set-util.c
@@ -112,3 +112,49 @@ int parse_cpu_set_and_warn(
return (int) ncpus;
}
+
+int parse_cpu_set(
+ const char *rvalue,
+ cpu_set_t **cpu_set) {
+
+ _cleanup_cpu_free_ cpu_set_t *c = NULL;
+ unsigned ncpus = 0;
+
+ assert(rvalue);
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+ unsigned cpu, cpu_lower, cpu_upper;
+ int r;
+
+ r = extract_first_word(&rvalue, &word, WHITESPACE ",", EXTRACT_QUOTES);
+ if (r == -ENOMEM)
+ return r;
+ if (r <= 0)
+ break;
+
+ if (!c) {
+ c = cpu_set_malloc(&ncpus);
+ if (!c)
+ return -ENOMEM;
+ }
+
+ r = parse_range(word, &cpu_lower, &cpu_upper);
+ if (r < 0)
+ return r;
+ if (cpu_lower >= ncpus || cpu_upper >= ncpus)
+ return -EINVAL;
+
+ if (cpu_lower <= cpu_upper)
+ for (cpu = cpu_lower; cpu <= cpu_upper; cpu++)
+ CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c);
+ }
+
+ /* On success, sets *cpu_set and returns ncpus for the system. */
+ if (c) {
+ *cpu_set = c;
+ c = NULL;
+ }
+
+ return (int) ncpus;
+}
diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h
index 6f49d9afb0..9b08ba0a67 100644
--- a/src/basic/cpu-set-util.h
+++ b/src/basic/cpu-set-util.h
@@ -30,3 +30,4 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE);
cpu_set_t* cpu_set_malloc(unsigned *ncpus);
int parse_cpu_set_and_warn(const char *rvalue, cpu_set_t **cpu_set, const char *unit, const char *filename, unsigned line, const char *lvalue);
+int parse_cpu_set(const char *rvalue, cpu_set_t **cpu_set);
diff --git a/src/basic/def.h b/src/basic/def.h
index b1a3bc190b..c04e58b57a 100644
--- a/src/basic/def.h
+++ b/src/basic/def.h
@@ -43,7 +43,7 @@
#define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT
#define SIGNALS_IGNORE SIGPIPE
-#ifdef HAVE_SPLIT_USR
+#if HAVE_SPLIT_USR
#define KBD_KEYMAP_DIRS \
"/usr/share/keymaps/\0" \
"/usr/share/kbd/keymaps/\0" \
@@ -57,10 +57,8 @@
#endif
#define UNIX_SYSTEM_BUS_ADDRESS "unix:path=/var/run/dbus/system_bus_socket"
-#define KERNEL_SYSTEM_BUS_ADDRESS "kernel:path=/sys/fs/kdbus/0-system/bus"
-#define DEFAULT_SYSTEM_BUS_ADDRESS KERNEL_SYSTEM_BUS_ADDRESS ";" UNIX_SYSTEM_BUS_ADDRESS
+#define DEFAULT_SYSTEM_BUS_ADDRESS UNIX_SYSTEM_BUS_ADDRESS
#define UNIX_USER_BUS_ADDRESS_FMT "unix:path=%s/bus"
-#define KERNEL_USER_BUS_ADDRESS_FMT "kernel:path=/sys/fs/kdbus/"UID_FMT"-user/bus"
#define PLYMOUTH_SOCKET { \
.un.sun_family = AF_UNIX, \
@@ -70,7 +68,7 @@
#define NOTIFY_FD_MAX 768
#define NOTIFY_BUFFER_MAX PIPE_BUF
-#ifdef HAVE_SPLIT_USR
+#if HAVE_SPLIT_USR
# define _CONF_PATHS_SPLIT_USR(n) "/lib/" n "\0"
#else
# define _CONF_PATHS_SPLIT_USR(n)
@@ -86,3 +84,5 @@
"/usr/local/lib/" n "\0" \
"/usr/lib/" n "\0" \
_CONF_PATHS_SPLIT_USR(n)
+
+#define LONG_LINE_MAX (1U*1024U*1024U)
diff --git a/src/basic/env-util.c b/src/basic/env-util.c
index 56e7b6fd8c..fa42edfa96 100644
--- a/src/basic/env-util.c
+++ b/src/basic/env-util.c
@@ -707,7 +707,7 @@ char **replace_env_argv(char **argv, char **env) {
STRV_FOREACH(i, argv) {
/* If $FOO appears as single word, replace it by the split up variable */
- if ((*i)[0] == '$' && (*i)[1] != '{' && (*i)[1] != '$') {
+ if ((*i)[0] == '$' && !IN_SET((*i)[1], '{', '$')) {
char *e;
char **w, **m = NULL;
unsigned q;
@@ -769,6 +769,16 @@ int getenv_bool(const char *p) {
return parse_boolean(e);
}
+int getenv_bool_secure(const char *p) {
+ const char *e;
+
+ e = secure_getenv(p);
+ if (!e)
+ return -ENXIO;
+
+ return parse_boolean(e);
+}
+
int serialize_environment(FILE *f, char **environment) {
char **e;
diff --git a/src/basic/env-util.h b/src/basic/env-util.h
index e88fa6aac0..d5da8cd67b 100644
--- a/src/basic/env-util.h
+++ b/src/basic/env-util.h
@@ -61,6 +61,7 @@ char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) _pure
char *strv_env_get(char **x, const char *n) _pure_;
int getenv_bool(const char *p);
+int getenv_bool_secure(const char *p);
int serialize_environment(FILE *f, char **environment);
int deserialize_environment(char ***environment, const char *line);
diff --git a/src/basic/escape.c b/src/basic/escape.c
index 85e4b5282e..0a6122c64a 100644
--- a/src/basic/escape.c
+++ b/src/basic/escape.c
@@ -314,7 +314,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi
/* Undoes C style string escaping, and optionally prefixes it. */
- pl = prefix ? strlen(prefix) : 0;
+ pl = strlen_ptr(prefix);
r = new(char, pl+length+1);
if (!r)
@@ -426,7 +426,7 @@ char *octescape(const char *s, size_t len) {
for (f = s, t = r; f < s + len; f++) {
- if (*f < ' ' || *f >= 127 || *f == '\\' || *f == '"') {
+ if (*f < ' ' || *f >= 127 || IN_SET(*f, '\\', '"')) {
*(t++) = '\\';
*(t++) = '0' + (*f >> 6);
*(t++) = '0' + ((*f >> 3) & 8);
diff --git a/src/basic/exec-util.c b/src/basic/exec-util.c
index aced9e8e3d..ade8511466 100644
--- a/src/basic/exec-util.c
+++ b/src/basic/exec-util.c
@@ -111,7 +111,7 @@ static int do_execute(
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
- r = conf_files_list_strv(&paths, NULL, NULL, (const char* const*) directories);
+ r = conf_files_list_strv(&paths, NULL, NULL, CONF_FILES_EXECUTABLE, (const char* const*) directories);
if (r < 0)
return r;
diff --git a/src/basic/exit-status.c b/src/basic/exit-status.c
index 1e23c32c3f..7cfebbae72 100644
--- a/src/basic/exit-status.c
+++ b/src/basic/exit-status.c
@@ -140,9 +140,6 @@ const char* exit_status_to_string(int status, ExitStatusLevel level) {
case EXIT_RUNTIME_DIRECTORY:
return "RUNTIME_DIRECTORY";
- case EXIT_MAKE_STARTER:
- return "MAKE_STARTER";
-
case EXIT_CHOWN:
return "CHOWN";
@@ -151,6 +148,18 @@ const char* exit_status_to_string(int status, ExitStatusLevel level) {
case EXIT_KEYRING:
return "KEYRING";
+
+ case EXIT_STATE_DIRECTORY:
+ return "STATE_DIRECTORY";
+
+ case EXIT_CACHE_DIRECTORY:
+ return "CACHE_DIRECTORY";
+
+ case EXIT_LOGS_DIRECTORY:
+ return "LOGS_DIRECTORY";
+
+ case EXIT_CONFIGURATION_DIRECTORY:
+ return "CONFIGURATION_DIRECTORY";
}
}
diff --git a/src/basic/exit-status.h b/src/basic/exit-status.h
index d22b2c00e4..195b3bc486 100644
--- a/src/basic/exit-status.h
+++ b/src/basic/exit-status.h
@@ -79,10 +79,14 @@ enum {
EXIT_APPARMOR_PROFILE,
EXIT_ADDRESS_FAMILIES,
EXIT_RUNTIME_DIRECTORY,
- EXIT_MAKE_STARTER,
+ _EXIT_RESERVED2, /* used to be used by kdbus, don't reuse */
EXIT_CHOWN,
EXIT_SMACK_PROCESS_LABEL,
EXIT_KEYRING,
+ EXIT_STATE_DIRECTORY,
+ EXIT_CACHE_DIRECTORY,
+ EXIT_LOGS_DIRECTORY, /* 240 */
+ EXIT_CONFIGURATION_DIRECTORY,
};
typedef enum ExitStatusLevel {
diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c
index 804f14c44c..f4ac526eb1 100644
--- a/src/basic/extract-word.c
+++ b/src/basic/extract-word.c
@@ -152,7 +152,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
for (;; (*p)++, c = **p) {
if (c == 0)
goto finish_force_terminate;
- else if ((c == '\'' || c == '"') && (flags & EXTRACT_QUOTES)) {
+ else if (IN_SET(c, '\'', '"') && (flags & EXTRACT_QUOTES)) {
quote = c;
break;
} else if (c == '\\' && !(flags & EXTRACT_RETAIN_ESCAPE)) {
diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c
index 19ad20789b..9d61044c89 100644
--- a/src/basic/fd-util.c
+++ b/src/basic/fd-util.c
@@ -31,6 +31,7 @@
#include "missing.h"
#include "parse-util.h"
#include "path-util.h"
+#include "process-util.h"
#include "socket-util.h"
#include "stdio-util.h"
#include "util.h"
@@ -282,7 +283,7 @@ int same_fd(int a, int b) {
return true;
/* Try to use kcmp() if we have it. */
- pid = getpid();
+ pid = getpid_cached();
r = kcmp(pid, pid, KCMP_FILE, a, b);
if (r == 0)
return true;
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index 9a185e3e60..9ee7a4af38 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -30,6 +30,7 @@
#include "alloc-util.h"
#include "ctype.h"
+#include "def.h"
#include "env-util.h"
#include "escape.h"
#include "fd-util.h"
@@ -41,6 +42,7 @@
#include "missing.h"
#include "parse-util.h"
#include "path-util.h"
+#include "process-util.h"
#include "random-util.h"
#include "stdio-util.h"
#include "string-util.h"
@@ -51,13 +53,17 @@
#define READ_FULL_BYTES_MAX (4U*1024U*1024U)
-int write_string_stream_ts(FILE *f, const char *line, bool enforce_newline, struct timespec *ts) {
+int write_string_stream_ts(
+ FILE *f,
+ const char *line,
+ WriteStringFileFlags flags,
+ struct timespec *ts) {
assert(f);
assert(line);
fputs(line, f);
- if (enforce_newline && !endswith(line, "\n"))
+ if (!(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n"))
fputc('\n', f);
if (ts) {
@@ -67,10 +73,18 @@ int write_string_stream_ts(FILE *f, const char *line, bool enforce_newline, stru
return -errno;
}
- return fflush_and_check(f);
+ if (flags & WRITE_STRING_FILE_SYNC)
+ return fflush_sync_and_check(f);
+ else
+ return fflush_and_check(f);
}
-static int write_string_file_atomic(const char *fn, const char *line, bool enforce_newline) {
+static int write_string_file_atomic(
+ const char *fn,
+ const char *line,
+ WriteStringFileFlags flags,
+ struct timespec *ts) {
+
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *p = NULL;
int r;
@@ -84,29 +98,41 @@ static int write_string_file_atomic(const char *fn, const char *line, bool enfor
(void) fchmod_umask(fileno(f), 0644);
- r = write_string_stream(f, line, enforce_newline);
- if (r >= 0) {
- if (rename(p, fn) < 0)
- r = -errno;
+ r = write_string_stream_ts(f, line, flags, ts);
+ if (r < 0)
+ goto fail;
+
+ if (rename(p, fn) < 0) {
+ r = -errno;
+ goto fail;
}
- if (r < 0)
- (void) unlink(p);
+ return 0;
+fail:
+ (void) unlink(p);
return r;
}
-int write_string_file_ts(const char *fn, const char *line, WriteStringFileFlags flags, struct timespec *ts) {
+int write_string_file_ts(
+ const char *fn,
+ const char *line,
+ WriteStringFileFlags flags,
+ struct timespec *ts) {
+
_cleanup_fclose_ FILE *f = NULL;
int q, r;
assert(fn);
assert(line);
+ /* We don't know how to verify whether the file contents was already on-disk. */
+ assert(!((flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE) && (flags & WRITE_STRING_FILE_SYNC)));
+
if (flags & WRITE_STRING_FILE_ATOMIC) {
assert(flags & WRITE_STRING_FILE_CREATE);
- r = write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
+ r = write_string_file_atomic(fn, line, flags, ts);
if (r < 0)
goto fail;
@@ -139,7 +165,7 @@ int write_string_file_ts(const char *fn, const char *line, WriteStringFileFlags
}
}
- r = write_string_stream_ts(f, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE), ts);
+ r = write_string_stream_ts(f, line, flags, ts);
if (r < 0)
goto fail;
@@ -163,7 +189,7 @@ fail:
int read_one_line_file(const char *fn, char **line) {
_cleanup_fclose_ FILE *f = NULL;
- char t[LINE_MAX], *c;
+ int r;
assert(fn);
assert(line);
@@ -172,21 +198,8 @@ int read_one_line_file(const char *fn, char **line) {
if (!f)
return -errno;
- if (!fgets(t, sizeof(t), f)) {
-
- if (ferror(f))
- return errno > 0 ? -errno : -EIO;
-
- t[0] = 0;
- }
-
- c = strdup(t);
- if (!c)
- return -ENOMEM;
- truncate_nl(c);
-
- *line = c;
- return 0;
+ r = read_line(f, LONG_LINE_MAX, line);
+ return r < 0 ? r : 0;
}
int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
@@ -245,11 +258,11 @@ int read_full_stream(FILE *f, char **contents, size_t *size) {
if (st.st_size > READ_FULL_BYTES_MAX)
return -E2BIG;
- /* Start with the right file size, but be prepared for
- * files from /proc which generally report a file size
- * of 0 */
+ /* Start with the right file size, but be prepared for files from /proc which generally report a file
+ * size of 0. Note that we increase the size to read here by one, so that the first read attempt
+ * already makes us notice the EOF. */
if (st.st_size > 0)
- n = st.st_size;
+ n = st.st_size + 1;
}
l = 0;
@@ -262,12 +275,13 @@ int read_full_stream(FILE *f, char **contents, size_t *size) {
return -ENOMEM;
buf = t;
+ errno = 0;
k = fread(buf + l, 1, n - l, f);
if (k > 0)
l += k;
if (ferror(f))
- return -errno;
+ return errno > 0 ? -errno : -EIO;
if (feof(f))
break;
@@ -823,29 +837,29 @@ static void write_env_var(FILE *f, const char *v) {
p = strchr(v, '=');
if (!p) {
/* Fallback */
- fputs(v, f);
- fputc('\n', f);
+ fputs_unlocked(v, f);
+ fputc_unlocked('\n', f);
return;
}
p++;
- fwrite(v, 1, p-v, f);
+ fwrite_unlocked(v, 1, p-v, f);
if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
- fputc('\"', f);
+ fputc_unlocked('\"', f);
for (; *p; p++) {
if (strchr(SHELL_NEED_ESCAPE, *p))
- fputc('\\', f);
+ fputc_unlocked('\\', f);
- fputc(*p, f);
+ fputc_unlocked(*p, f);
}
- fputc('\"', f);
+ fputc_unlocked('\"', f);
} else
- fputs(p, f);
+ fputs_unlocked(p, f);
- fputc('\n', f);
+ fputc_unlocked('\n', f);
}
int write_env_file(const char *fname, char **l) {
@@ -1125,6 +1139,21 @@ int fflush_and_check(FILE *f) {
return 0;
}
+int fflush_sync_and_check(FILE *f) {
+ int r;
+
+ assert(f);
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
+
+ if (fsync(fileno(f)) < 0)
+ return -errno;
+
+ return 0;
+}
+
/* This is much like mkostemp() but is subject to umask(). */
int mkostemp_safe(char *pattern) {
_cleanup_umask_ mode_t u = 0;
@@ -1399,7 +1428,7 @@ int open_serialization_fd(const char *ident) {
if (fd < 0) {
const char *path;
- path = getpid() == 1 ? "/run/systemd" : "/tmp";
+ path = getpid_cached() == 1 ? "/run/systemd" : "/tmp";
fd = open_tmpfile_unlinkable(path, O_RDWR|O_CLOEXEC);
if (fd < 0)
return fd;
@@ -1497,3 +1526,77 @@ int mkdtemp_malloc(const char *template, char **ret) {
*ret = p;
return 0;
}
+
+static inline void funlockfilep(FILE **f) {
+ funlockfile(*f);
+}
+
+int read_line(FILE *f, size_t limit, char **ret) {
+ _cleanup_free_ char *buffer = NULL;
+ size_t n = 0, allocated = 0, count = 0;
+
+ assert(f);
+
+ /* Something like a bounded version of getline().
+ *
+ * Considers EOF, \n and \0 end of line delimiters, and does not include these delimiters in the string
+ * returned.
+ *
+ * Returns the number of bytes read from the files (i.e. including delimiters — this hence usually differs from
+ * the number of characters in the returned string). When EOF is hit, 0 is returned.
+ *
+ * The input parameter limit is the maximum numbers of characters in the returned string, i.e. excluding
+ * delimiters. If the limit is hit we fail and return -ENOBUFS.
+ *
+ * If a line shall be skipped ret may be initialized as NULL. */
+
+ if (ret) {
+ if (!GREEDY_REALLOC(buffer, allocated, 1))
+ return -ENOMEM;
+ }
+
+ {
+ _cleanup_(funlockfilep) FILE *flocked = f;
+ flockfile(f);
+
+ for (;;) {
+ int c;
+
+ if (n >= limit)
+ return -ENOBUFS;
+
+ errno = 0;
+ c = fgetc_unlocked(f);
+ if (c == EOF) {
+ /* if we read an error, and have no data to return, then propagate the error */
+ if (ferror_unlocked(f) && n == 0)
+ return errno > 0 ? -errno : -EIO;
+
+ break;
+ }
+
+ count++;
+
+ if (IN_SET(c, '\n', 0)) /* Reached a delimiter */
+ break;
+
+ if (ret) {
+ if (!GREEDY_REALLOC(buffer, allocated, n + 2))
+ return -ENOMEM;
+
+ buffer[n] = (char) c;
+ }
+
+ n++;
+ }
+ }
+
+ if (ret) {
+ buffer[n] = 0;
+
+ *ret = buffer;
+ buffer = NULL;
+ }
+
+ return (int) count;
+}
diff --git a/src/basic/fileio.h b/src/basic/fileio.h
index 6098562265..eba05be2a9 100644
--- a/src/basic/fileio.h
+++ b/src/basic/fileio.h
@@ -29,15 +29,16 @@
#include "time-util.h"
typedef enum {
- WRITE_STRING_FILE_CREATE = 1,
- WRITE_STRING_FILE_ATOMIC = 2,
- WRITE_STRING_FILE_AVOID_NEWLINE = 4,
- WRITE_STRING_FILE_VERIFY_ON_FAILURE = 8,
+ WRITE_STRING_FILE_CREATE = 1<<0,
+ WRITE_STRING_FILE_ATOMIC = 1<<1,
+ WRITE_STRING_FILE_AVOID_NEWLINE = 1<<2,
+ WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1<<3,
+ WRITE_STRING_FILE_SYNC = 1<<4,
} WriteStringFileFlags;
-int write_string_stream_ts(FILE *f, const char *line, bool enforce_newline, struct timespec *ts);
-static inline int write_string_stream(FILE *f, const char *line, bool enforce_newline) {
- return write_string_stream_ts(f, line, enforce_newline, NULL);
+int write_string_stream_ts(FILE *f, const char *line, WriteStringFileFlags flags, struct timespec *ts);
+static inline int write_string_stream(FILE *f, const char *line, WriteStringFileFlags flags) {
+ return write_string_stream_ts(f, line, flags, NULL);
}
int write_string_file_ts(const char *fn, const char *line, WriteStringFileFlags flags, struct timespec *ts);
static inline int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
@@ -77,6 +78,7 @@ int search_and_fopen_nulstr(const char *path, const char *mode, const char *root
} else
int fflush_and_check(FILE *f);
+int fflush_sync_and_check(FILE *f);
int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
int mkostemp_safe(char *pattern);
@@ -99,3 +101,5 @@ int link_tmpfile(int fd, const char *path, const char *target);
int read_nul_string(FILE *f, char **ret);
int mkdtemp_malloc(const char *template, char **ret);
+
+int read_line(FILE *f, size_t limit, char **ret);
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index 8fe19ee4e4..b90f343ed3 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
+#include <linux/magic.h>
#include <time.h>
#include <unistd.h>
@@ -307,7 +308,7 @@ int fd_warn_permissions(const char *path, int fd) {
if (st.st_mode & 0002)
log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path);
- if (getpid() == 1 && (st.st_mode & 0044) != 0044)
+ if (getpid_cached() == 1 && (st.st_mode & 0044) != 0044)
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);
return 0;
@@ -323,7 +324,7 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi
mkdir_parents(path, 0755);
fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY,
- (mode == 0 || mode == MODE_INVALID) ? 0644 : mode);
+ IN_SET(mode, 0, MODE_INVALID) ? 0644 : mode);
if (fd < 0)
return -errno;
@@ -358,22 +359,25 @@ int touch(const char *path) {
}
int symlink_idempotent(const char *from, const char *to) {
- _cleanup_free_ char *p = NULL;
int r;
assert(from);
assert(to);
if (symlink(from, to) < 0) {
+ _cleanup_free_ char *p = NULL;
+
if (errno != EEXIST)
return -errno;
r = readlink_malloc(to, &p);
- if (r < 0)
+ if (r == -EINVAL) /* Not a symlink? In that case return the original error we encountered: -EEXIST */
+ return -EEXIST;
+ if (r < 0) /* Any other error? In that case propagate it as is */
return r;
- if (!streq(p, from))
- return -EINVAL;
+ if (!streq(p, from)) /* Not the symlink we want it to be? In that case, propagate the original -EEXIST */
+ return -EEXIST;
}
return 0;
@@ -721,6 +725,9 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
if (fstat(child, &st) < 0)
return -errno;
+ if ((flags & CHASE_NO_AUTOFS) &&
+ fd_check_fstype(child, AUTOFS_SUPER_MAGIC) > 0)
+ return -EREMOTE;
if (S_ISLNK(st.st_mode)) {
char *joined;
diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h
index 094acf1799..d3342d5cda 100644
--- a/src/basic/fs-util.h
+++ b/src/basic/fs-util.h
@@ -81,6 +81,7 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask);
enum {
CHASE_PREFIX_ROOT = 1, /* If set, the specified path will be prefixed by the specified root before beginning the iteration */
CHASE_NONEXISTENT = 2, /* If set, it's OK if the path doesn't actually exist. */
+ CHASE_NO_AUTOFS = 4, /* If set, return -EREMOTE if autofs mount point found */
};
int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret);
diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c
index 50fefb0b54..4bfaa864b4 100644
--- a/src/basic/hashmap.c
+++ b/src/basic/hashmap.c
@@ -34,7 +34,7 @@
#include "strv.h"
#include "util.h"
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
#include <pthread.h>
#include "list.h"
#endif
@@ -142,7 +142,7 @@ typedef uint8_t dib_raw_t;
#define DIB_FREE UINT_MAX
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
struct hashmap_debug_info {
LIST_FIELDS(struct hashmap_debug_info, debug_list);
unsigned max_entries; /* high watermark of n_entries */
@@ -499,7 +499,7 @@ static void base_remove_entry(HashmapBase *h, unsigned idx) {
dibs = dib_raw_ptr(h);
assert(dibs[idx] != DIB_RAW_FREE);
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
h->debug.rem_count++;
h->debug.last_rem_idx = idx;
#endif
@@ -508,7 +508,7 @@ static void base_remove_entry(HashmapBase *h, unsigned idx) {
/* Find the stop bucket ("right"). It is either free or has DIB == 0. */
for (right = next_idx(h, left); ; right = next_idx(h, right)) {
raw_dib = dibs[right];
- if (raw_dib == 0 || raw_dib == DIB_RAW_FREE)
+ if (IN_SET(raw_dib, 0, DIB_RAW_FREE))
break;
/* The buckets are not supposed to be all occupied and with DIB > 0.
@@ -578,7 +578,7 @@ static unsigned hashmap_iterate_in_insertion_order(OrderedHashmap *h, Iterator *
assert(e->p.b.key == i->next_key);
}
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
i->prev_idx = idx;
#endif
@@ -635,7 +635,7 @@ static unsigned hashmap_iterate_in_internal_order(HashmapBase *h, Iterator *i) {
}
idx = i->idx;
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
i->prev_idx = idx;
#endif
@@ -658,7 +658,7 @@ static unsigned hashmap_iterate_entry(HashmapBase *h, Iterator *i) {
return IDX_NIL;
}
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
if (i->idx == IDX_FIRST) {
i->put_count = h->debug.put_count;
i->rem_count = h->debug.rem_count;
@@ -750,7 +750,7 @@ static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enu
shared_hash_key_initialized= true;
}
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
h->debug.func = func;
h->debug.file = file;
h->debug.line = line;
@@ -807,7 +807,7 @@ static void hashmap_free_no_clear(HashmapBase *h) {
assert(!h->has_indirect);
assert(!h->n_direct_entries);
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
assert_se(pthread_mutex_lock(&hashmap_debug_list_mutex) == 0);
LIST_REMOVE(debug_list, hashmap_debug_list, &h->debug);
assert_se(pthread_mutex_unlock(&hashmap_debug_list_mutex) == 0);
@@ -919,7 +919,7 @@ static bool hashmap_put_robin_hood(HashmapBase *h, unsigned idx,
dib_raw_t raw_dib, *dibs;
unsigned dib, distance;
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
h->debug.put_count++;
#endif
@@ -927,7 +927,7 @@ static bool hashmap_put_robin_hood(HashmapBase *h, unsigned idx,
for (distance = 0; ; distance++) {
raw_dib = dibs[idx];
- if (raw_dib == DIB_RAW_FREE || raw_dib == DIB_RAW_REHASH) {
+ if (IN_SET(raw_dib, DIB_RAW_FREE, DIB_RAW_REHASH)) {
if (raw_dib == DIB_RAW_REHASH)
bucket_move_entry(h, swap, idx, IDX_TMP);
@@ -1012,7 +1012,7 @@ static int hashmap_base_put_boldly(HashmapBase *h, unsigned idx,
assert_se(hashmap_put_robin_hood(h, idx, swap) == false);
n_entries_inc(h);
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
h->debug.max_entries = MAX(h->debug.max_entries, n_entries(h));
#endif
@@ -1240,7 +1240,7 @@ int hashmap_replace(Hashmap *h, const void *key, void *value) {
idx = bucket_scan(h, hash, key);
if (idx != IDX_NIL) {
e = plain_bucket_at(h, idx);
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
/* Although the key is equal, the key pointer may have changed,
* and this would break our assumption for iterating. So count
* this operation as incompatible with iteration. */
diff --git a/src/basic/hashmap.h b/src/basic/hashmap.h
index 6d1ae48b21..c1089652d3 100644
--- a/src/basic/hashmap.h
+++ b/src/basic/hashmap.h
@@ -58,7 +58,7 @@ typedef struct Set Set; /* Stores just keys */
typedef struct {
unsigned idx; /* index of an entry to be iterated next */
const void *next_key; /* expected value of that entry's key pointer */
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
unsigned put_count; /* hashmap's put_count recorded at start of iteration */
unsigned rem_count; /* hashmap's rem_count in previous iteration */
unsigned prev_idx; /* idx in previous iteration */
@@ -89,7 +89,7 @@ typedef struct {
(Hashmap*)(h), \
(void)0)
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
# define HASHMAP_DEBUG_PARAMS , const char *func, const char *file, int line
# define HASHMAP_DEBUG_SRC_ARGS , __func__, __FILE__, __LINE__
# define HASHMAP_DEBUG_PASS_ARGS , func, file, line
diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c
index 2d6e377f0a..766770389c 100644
--- a/src/basic/hexdecoct.c
+++ b/src/basic/hexdecoct.c
@@ -25,6 +25,7 @@
#include "alloc-util.h"
#include "hexdecoct.h"
#include "macro.h"
+#include "string-util.h"
#include "util.h"
char octchar(int x) {
@@ -569,7 +570,7 @@ static int base64_append_width(char **prefix, int plen,
lines = (len + width - 1) / width;
- slen = sep ? strlen(sep) : 0;
+ slen = strlen_ptr(sep);
t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
if (!t)
return -ENOMEM;
diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c
index a94037b303..ea9e77087f 100644
--- a/src/basic/hostname-util.c
+++ b/src/basic/hostname-util.c
@@ -90,9 +90,7 @@ static bool hostname_valid_char(char c) {
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') ||
- c == '-' ||
- c == '_' ||
- c == '.';
+ IN_SET(c, '-', '_', '.');
}
/**
@@ -196,8 +194,11 @@ bool is_gateway_hostname(const char *hostname) {
* synthetic "gateway" host. */
return
- strcaseeq(hostname, "gateway") ||
- strcaseeq(hostname, "gateway.");
+ strcaseeq(hostname, "_gateway") || strcaseeq(hostname, "_gateway.")
+#if ENABLE_COMPAT_GATEWAY_HOSTNAME
+ || strcaseeq(hostname, "gateway") || strcaseeq(hostname, "gateway.")
+#endif
+ ;
}
int sethostname_idempotent(const char *s) {
@@ -232,7 +233,7 @@ int read_hostname_config(const char *path, char **hostname) {
/* may have comments, ignore them */
FOREACH_LINE(l, f, return -errno) {
truncate_nl(l);
- if (l[0] != '\0' && l[0] != '#') {
+ if (!IN_SET(l[0], '\0', '#')) {
/* found line with value */
name = hostname_cleanup(l);
name = strdup(name);
diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c
index d52fdad3ac..e27faba75f 100644
--- a/src/basic/in-addr-util.c
+++ b/src/basic/in-addr-util.c
@@ -308,22 +308,22 @@ int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
return 0;
}
-int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret) {
+int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret) {
int r;
assert(s);
r = in_addr_from_string(AF_INET, s, ret);
if (r >= 0) {
- if (family)
- *family = AF_INET;
+ if (ret_family)
+ *ret_family = AF_INET;
return 0;
}
r = in_addr_from_string(AF_INET6, s, ret);
if (r >= 0) {
- if (family)
- *family = AF_INET6;
+ if (ret_family)
+ *ret_family = AF_INET6;
return 0;
}
@@ -371,13 +371,13 @@ int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_u
return r;
}
-unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr) {
+unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr) {
assert(addr);
return 32 - u32ctz(be32toh(addr->s_addr));
}
-struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
+struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
assert(addr);
assert(prefixlen <= 32);
@@ -390,7 +390,7 @@ struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char
return addr;
}
-int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
+int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
uint8_t msb_octet = *(uint8_t*) addr;
/* addr may not be aligned, so make sure we only access it byte-wise */
@@ -414,18 +414,18 @@ int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixl
return 0;
}
-int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) {
+int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) {
unsigned char prefixlen;
int r;
assert(addr);
assert(mask);
- r = in_addr_default_prefixlen(addr, &prefixlen);
+ r = in4_addr_default_prefixlen(addr, &prefixlen);
if (r < 0)
return r;
- in_addr_prefixlen_to_netmask(mask, prefixlen);
+ in4_addr_prefixlen_to_netmask(mask, prefixlen);
return 0;
}
@@ -435,7 +435,7 @@ int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen)
if (family == AF_INET) {
struct in_addr mask;
- if (!in_addr_prefixlen_to_netmask(&mask, prefixlen))
+ if (!in4_addr_prefixlen_to_netmask(&mask, prefixlen))
return -EINVAL;
addr->in.s_addr &= mask.s_addr;
@@ -465,10 +465,57 @@ int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen)
return -EAFNOSUPPORT;
}
-int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, uint8_t *ret_prefixlen) {
+int in_addr_prefix_covers(int family,
+ const union in_addr_union *prefix,
+ unsigned char prefixlen,
+ const union in_addr_union *address) {
+
+ union in_addr_union masked_prefix, masked_address;
+ int r;
+
+ assert(prefix);
+ assert(address);
+
+ masked_prefix = *prefix;
+ r = in_addr_mask(family, &masked_prefix, prefixlen);
+ if (r < 0)
+ return r;
+
+ masked_address = *address;
+ r = in_addr_mask(family, &masked_address, prefixlen);
+ if (r < 0)
+ return r;
+
+ return in_addr_equal(family, &masked_prefix, &masked_address);
+}
+
+int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) {
+ uint8_t u;
+ int r;
+
+ if (!IN_SET(family, AF_INET, AF_INET6))
+ return -EAFNOSUPPORT;
+
+ r = safe_atou8(p, &u);
+ if (r < 0)
+ return r;
+
+ if (u > FAMILY_ADDRESS_SIZE(family) * 8)
+ return -ERANGE;
+
+ *ret = u;
+ return 0;
+}
+
+int in_addr_prefix_from_string(
+ const char *p,
+ int family,
+ union in_addr_union *ret_prefix,
+ unsigned char *ret_prefixlen) {
+
union in_addr_union buffer;
const char *e, *l;
- uint8_t k;
+ unsigned char k;
int r;
assert(p);
@@ -486,23 +533,58 @@ int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *r
if (r < 0)
return r;
- k = FAMILY_ADDRESS_SIZE(family) * 8;
-
if (e) {
- uint8_t n;
-
- r = safe_atou8(e + 1, &n);
+ r = in_addr_parse_prefixlen(family, e+1, &k);
if (r < 0)
return r;
+ } else
+ k = FAMILY_ADDRESS_SIZE(family) * 8;
- if (n > k)
- return -ERANGE;
+ if (ret_prefix)
+ *ret_prefix = buffer;
+ if (ret_prefixlen)
+ *ret_prefixlen = k;
- k = n;
- }
+ return 0;
+}
+
+int in_addr_prefix_from_string_auto(
+ const char *p,
+ int *ret_family,
+ union in_addr_union *ret_prefix,
+ unsigned char *ret_prefixlen) {
+
+ union in_addr_union buffer;
+ const char *e, *l;
+ unsigned char k;
+ int family, r;
+
+ assert(p);
+
+ e = strchr(p, '/');
+ if (e)
+ l = strndupa(p, e - p);
+ else
+ l = p;
- *ret_prefix = buffer;
- *ret_prefixlen = k;
+ r = in_addr_from_string_auto(l, &family, &buffer);
+ if (r < 0)
+ return r;
+
+ if (e) {
+ r = in_addr_parse_prefixlen(family, e+1, &k);
+ if (r < 0)
+ return r;
+ } else
+ k = FAMILY_ADDRESS_SIZE(family) * 8;
+
+ if (ret_family)
+ *ret_family = family;
+ if (ret_prefix)
+ *ret_prefix = buffer;
+ if (ret_prefixlen)
+ *ret_prefixlen = k;
return 0;
+
}
diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h
index 14e27246b5..59f8eb7edf 100644
--- a/src/basic/in-addr-util.h
+++ b/src/basic/in-addr-util.h
@@ -53,17 +53,20 @@ int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen);
int in_addr_to_string(int family, const union in_addr_union *u, char **ret);
int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret);
int in_addr_from_string(int family, const char *s, union in_addr_union *ret);
-int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret);
+int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret);
int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex);
-unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr);
-struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
-int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
-int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask);
+unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr);
+struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
+int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
+int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask);
int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen);
-int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, uint8_t *ret_prefixlen);
+int in_addr_prefix_covers(int family, const union in_addr_union *prefix, unsigned char prefixlen, const union in_addr_union *address);
+int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret);
+int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
+int in_addr_prefix_from_string_auto(const char *p, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
static inline size_t FAMILY_ADDRESS_SIZE(int family) {
- assert(family == AF_INET || family == AF_INET6);
+ assert(IN_SET(family, AF_INET, AF_INET6));
return family == AF_INET6 ? 16 : 4;
}
diff --git a/src/basic/io-util.h b/src/basic/io-util.h
index 4684ed3bfc..d9b69adde9 100644
--- a/src/basic/io-util.h
+++ b/src/basic/io-util.h
@@ -40,14 +40,6 @@ int fd_wait_for_event(int fd, int event, usec_t timeout);
ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
-#define IOVEC_SET_STRING(i, s) \
- do { \
- struct iovec *_i = &(i); \
- char *_s = (char *)(s); \
- _i->iov_base = _s; \
- _i->iov_len = strlen(_s); \
- } while (false)
-
static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) {
unsigned j;
size_t r = 0;
@@ -93,3 +85,8 @@ static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) {
return FILE_SIZE_VALID(l);
}
+
+#define IOVEC_INIT(base, len) { .iov_base = (base), .iov_len = (len) }
+#define IOVEC_MAKE(base, len) (struct iovec) IOVEC_INIT(base, len)
+#define IOVEC_INIT_STRING(string) IOVEC_INIT((char*) string, strlen(string))
+#define IOVEC_MAKE_STRING(string) (struct iovec) IOVEC_INIT_STRING(string)
diff --git a/src/basic/journal-importer.c b/src/basic/journal-importer.c
index 7d72effdea..e750101165 100644
--- a/src/basic/journal-importer.c
+++ b/src/basic/journal-importer.c
@@ -20,8 +20,9 @@
#include <unistd.h>
#include "alloc-util.h"
-#include "journal-importer.h"
#include "fd-util.h"
+#include "io-util.h"
+#include "journal-importer.h"
#include "parse-util.h"
#include "string-util.h"
#include "unaligned.h"
@@ -38,7 +39,7 @@ static int iovw_put(struct iovec_wrapper *iovw, void* data, size_t len) {
if (!GREEDY_REALLOC(iovw->iovec, iovw->size_bytes, iovw->count + 1))
return log_oom();
- iovw->iovec[iovw->count++] = (struct iovec) {data, len};
+ iovw->iovec[iovw->count++] = IOVEC_MAKE(data, len);
return 0;
}
@@ -153,9 +154,7 @@ static int get_line(JournalImporter *imp, char **line, size_t *size) {
static int fill_fixed_size(JournalImporter *imp, void **data, size_t size) {
assert(imp);
- assert(imp->state == IMPORTER_STATE_DATA_START ||
- imp->state == IMPORTER_STATE_DATA ||
- imp->state == IMPORTER_STATE_DATA_FINISH);
+ assert(IN_SET(imp->state, IMPORTER_STATE_DATA_START, IMPORTER_STATE_DATA, IMPORTER_STATE_DATA_FINISH));
assert(size <= DATA_SIZE_MAX);
assert(imp->offset <= imp->filled);
assert(imp->filled <= imp->size);
diff --git a/src/basic/log.c b/src/basic/log.c
index 3fd53800a0..4f0fe54579 100644
--- a/src/basic/log.c
+++ b/src/basic/log.c
@@ -74,6 +74,7 @@ static bool show_location = false;
static bool upgrade_syslog_to_journal = false;
static bool always_reopen_console = false;
+static bool open_when_needed = false;
/* Akin to glibc's __abort_msg; which is private and we hence cannot
* use here. */
@@ -84,7 +85,7 @@ void log_close_console(void) {
if (console_fd < 0)
return;
- if (getpid() == 1) {
+ if (getpid_cached() == 1) {
if (console_fd >= 3)
safe_close(console_fd);
@@ -140,7 +141,7 @@ static int create_log_socket(int type) {
/* We need a blocking fd here since we'd otherwise lose
messages way too early. However, let's not hang forever in the
unlikely case of a deadlock. */
- if (getpid() == 1)
+ if (getpid_cached() == 1)
timeval_store(&tv, 10 * USEC_PER_MSEC);
else
timeval_store(&tv, 10 * USEC_PER_SEC);
@@ -248,7 +249,7 @@ int log_open(void) {
}
if (!IN_SET(log_target, LOG_TARGET_AUTO, LOG_TARGET_SAFE) ||
- getpid() == 1 ||
+ getpid_cached() == 1 ||
isatty(STDERR_FILENO) <= 0) {
if (IN_SET(log_target, LOG_TARGET_AUTO,
@@ -351,26 +352,26 @@ static int write_to_console(
if (log_target == LOG_TARGET_CONSOLE_PREFIXED) {
xsprintf(prefix, "<%i>", level);
- IOVEC_SET_STRING(iovec[n++], prefix);
+ iovec[n++] = IOVEC_MAKE_STRING(prefix);
}
highlight = LOG_PRI(level) <= LOG_ERR && show_color;
if (show_location) {
snprintf(location, sizeof(location), "(%s:%i) ", file, line);
- IOVEC_SET_STRING(iovec[n++], location);
+ iovec[n++] = IOVEC_MAKE_STRING(location);
}
if (highlight)
- IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED);
- IOVEC_SET_STRING(iovec[n++], buffer);
+ iovec[n++] = IOVEC_MAKE_STRING(ANSI_HIGHLIGHT_RED);
+ iovec[n++] = IOVEC_MAKE_STRING(buffer);
if (highlight)
- IOVEC_SET_STRING(iovec[n++], ANSI_NORMAL);
- IOVEC_SET_STRING(iovec[n++], "\n");
+ iovec[n++] = IOVEC_MAKE_STRING(ANSI_NORMAL);
+ iovec[n++] = IOVEC_MAKE_STRING("\n");
if (writev(console_fd, iovec, n) < 0) {
- if (errno == EIO && getpid() == 1) {
+ if (errno == EIO && getpid_cached() == 1) {
/* If somebody tried to kick us from our
* console tty (via vhangup() or suchlike),
@@ -423,13 +424,13 @@ static int write_to_syslog(
if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
return -EINVAL;
- xsprintf(header_pid, "["PID_FMT"]: ", getpid());
+ xsprintf(header_pid, "["PID_FMT"]: ", getpid_cached());
- IOVEC_SET_STRING(iovec[0], header_priority);
- IOVEC_SET_STRING(iovec[1], header_time);
- IOVEC_SET_STRING(iovec[2], program_invocation_short_name);
- IOVEC_SET_STRING(iovec[3], header_pid);
- IOVEC_SET_STRING(iovec[4], buffer);
+ iovec[0] = IOVEC_MAKE_STRING(header_priority);
+ iovec[1] = IOVEC_MAKE_STRING(header_time);
+ iovec[2] = IOVEC_MAKE_STRING(program_invocation_short_name);
+ iovec[3] = IOVEC_MAKE_STRING(header_pid);
+ iovec[4] = IOVEC_MAKE_STRING(buffer);
/* When using syslog via SOCK_STREAM separate the messages by NUL chars */
if (syslog_is_stream)
@@ -468,13 +469,13 @@ static int write_to_kmsg(
return 0;
xsprintf(header_priority, "<%i>", level);
- xsprintf(header_pid, "["PID_FMT"]: ", getpid());
+ xsprintf(header_pid, "["PID_FMT"]: ", getpid_cached());
- IOVEC_SET_STRING(iovec[0], header_priority);
- IOVEC_SET_STRING(iovec[1], program_invocation_short_name);
- IOVEC_SET_STRING(iovec[2], header_pid);
- IOVEC_SET_STRING(iovec[3], buffer);
- IOVEC_SET_STRING(iovec[4], "\n");
+ iovec[0] = IOVEC_MAKE_STRING(header_priority);
+ iovec[1] = IOVEC_MAKE_STRING(program_invocation_short_name);
+ iovec[2] = IOVEC_MAKE_STRING(header_pid);
+ iovec[3] = IOVEC_MAKE_STRING(buffer);
+ iovec[4] = IOVEC_MAKE_STRING("\n");
if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
return -errno;
@@ -547,10 +548,10 @@ static int write_to_journal(
log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object, extra_field, extra);
- IOVEC_SET_STRING(iovec[0], header);
- IOVEC_SET_STRING(iovec[1], "MESSAGE=");
- IOVEC_SET_STRING(iovec[2], buffer);
- IOVEC_SET_STRING(iovec[3], "\n");
+ iovec[0] = IOVEC_MAKE_STRING(header);
+ iovec[1] = IOVEC_MAKE_STRING("MESSAGE=");
+ iovec[2] = IOVEC_MAKE_STRING(buffer);
+ iovec[3] = IOVEC_MAKE_STRING("\n");
mh.msg_iov = iovec;
mh.msg_iovlen = ELEMENTSOF(iovec);
@@ -585,6 +586,9 @@ int log_dispatch_internal(
if ((level & LOG_FACMASK) == 0)
level = log_facility | LOG_PRI(level);
+ if (open_when_needed)
+ log_open();
+
do {
char *e;
int k = 0;
@@ -640,6 +644,9 @@ int log_dispatch_internal(
buffer = e;
} while (buffer);
+ if (open_when_needed)
+ log_close();
+
return -error;
}
@@ -804,6 +811,7 @@ noreturn void log_assert_failed_realm(
const char *file,
int line,
const char *func) {
+ log_open();
log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_CRIT), text, file, line, func,
"Assertion '%s' failed at %s:%u, function %s(). Aborting.");
abort();
@@ -815,6 +823,7 @@ noreturn void log_assert_failed_unreachable_realm(
const char *file,
int line,
const char *func) {
+ log_open();
log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_CRIT), text, file, line, func,
"Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
abort();
@@ -832,9 +841,8 @@ void log_assert_failed_return_realm(
}
int log_oom_internal(LogRealm realm, const char *file, int line, const char *func) {
- log_internal_realm(LOG_REALM_PLUS_LEVEL(realm, LOG_ERR),
- ENOMEM, file, line, func, "Out of memory.");
- return -ENOMEM;
+ return log_internal_realm(LOG_REALM_PLUS_LEVEL(realm, LOG_ERR),
+ ENOMEM, file, line, func, "Out of memory.");
}
int log_format_iovec(
@@ -870,7 +878,7 @@ int log_format_iovec(
* the next format string */
VA_FORMAT_ADVANCE(format, ap);
- IOVEC_SET_STRING(iovec[(*n)++], m);
+ iovec[(*n)++] = IOVEC_MAKE_STRING(m);
if (newline_separator) {
iovec[*n].iov_base = (char*) &nl;
@@ -891,9 +899,9 @@ int log_struct_internal(
const char *func,
const char *format, ...) {
+ LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
char buf[LINE_MAX];
bool found = false;
- LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
PROTECT_ERRNO;
va_list ap;
@@ -909,38 +917,48 @@ int log_struct_internal(
if ((level & LOG_FACMASK) == 0)
level = log_facility | LOG_PRI(level);
- if (IN_SET(log_target, LOG_TARGET_AUTO,
- LOG_TARGET_JOURNAL_OR_KMSG,
- LOG_TARGET_JOURNAL) &&
- journal_fd >= 0) {
- char header[LINE_MAX];
- struct iovec iovec[17] = {};
- unsigned n = 0, i;
- int r;
- struct msghdr mh = {
- .msg_iov = iovec,
- };
- bool fallback = false;
-
- /* If the journal is available do structured logging */
- log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
- IOVEC_SET_STRING(iovec[n++], header);
+ if (IN_SET(log_target,
+ LOG_TARGET_AUTO,
+ LOG_TARGET_JOURNAL_OR_KMSG,
+ LOG_TARGET_JOURNAL)) {
+
+ if (open_when_needed)
+ log_open_journal();
+
+ if (journal_fd >= 0) {
+ char header[LINE_MAX];
+ struct iovec iovec[17] = {};
+ unsigned n = 0, i;
+ int r;
+ struct msghdr mh = {
+ .msg_iov = iovec,
+ };
+ bool fallback = false;
+
+ /* If the journal is available do structured logging */
+ log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
+ iovec[n++] = IOVEC_MAKE_STRING(header);
+
+ va_start(ap, format);
+ r = log_format_iovec(iovec, ELEMENTSOF(iovec), &n, true, error, format, ap);
+ if (r < 0)
+ fallback = true;
+ else {
+ mh.msg_iovlen = n;
+ (void) sendmsg(journal_fd, &mh, MSG_NOSIGNAL);
+ }
- va_start(ap, format);
- r = log_format_iovec(iovec, ELEMENTSOF(iovec), &n, true, error, format, ap);
- if (r < 0)
- fallback = true;
- else {
- mh.msg_iovlen = n;
- (void) sendmsg(journal_fd, &mh, MSG_NOSIGNAL);
- }
+ va_end(ap);
+ for (i = 1; i < n; i += 2)
+ free(iovec[i].iov_base);
- va_end(ap);
- for (i = 1; i < n; i += 2)
- free(iovec[i].iov_base);
+ if (!fallback) {
+ if (open_when_needed)
+ log_close();
- if (!fallback)
- return -error;
+ return -error;
+ }
+ }
}
/* Fallback if journal logging is not available or didn't work. */
@@ -967,12 +985,83 @@ int log_struct_internal(
}
va_end(ap);
- if (!found)
+ if (!found) {
+ if (open_when_needed)
+ log_close();
+
return -error;
+ }
return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buf + 8);
}
+int log_struct_iovec_internal(
+ int level,
+ int error,
+ const char *file,
+ int line,
+ const char *func,
+ const struct iovec input_iovec[],
+ size_t n_input_iovec) {
+
+ LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
+ PROTECT_ERRNO;
+ size_t i;
+ char *m;
+
+ if (error < 0)
+ error = -error;
+
+ if (_likely_(LOG_PRI(level) > log_max_level[realm]))
+ return -error;
+
+ if (log_target == LOG_TARGET_NULL)
+ return -error;
+
+ if ((level & LOG_FACMASK) == 0)
+ level = log_facility | LOG_PRI(level);
+
+ if (IN_SET(log_target, LOG_TARGET_AUTO,
+ LOG_TARGET_JOURNAL_OR_KMSG,
+ LOG_TARGET_JOURNAL) &&
+ journal_fd >= 0) {
+
+ struct iovec iovec[1 + n_input_iovec*2];
+ char header[LINE_MAX];
+ struct msghdr mh = {
+ .msg_iov = iovec,
+ .msg_iovlen = 1 + n_input_iovec*2,
+ };
+
+ log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
+ iovec[0] = IOVEC_MAKE_STRING(header);
+
+ for (i = 0; i < n_input_iovec; i++) {
+ iovec[1+i*2] = input_iovec[i];
+ iovec[1+i*2+1] = IOVEC_MAKE_STRING("\n");
+ }
+
+ if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) >= 0)
+ return -error;
+ }
+
+ for (i = 0; i < n_input_iovec; i++) {
+ if (input_iovec[i].iov_len < strlen("MESSAGE="))
+ continue;
+
+ if (memcmp(input_iovec[i].iov_base, "MESSAGE=", strlen("MESSAGE=")) == 0)
+ break;
+ }
+
+ if (_unlikely_(i >= n_input_iovec)) /* Couldn't find MESSAGE=? */
+ return -error;
+
+ m = strndupa(input_iovec[i].iov_base + strlen("MESSAGE="),
+ input_iovec[i].iov_len - strlen("MESSAGE="));
+
+ return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, m);
+}
+
int log_set_target_from_string(const char *e) {
LogTarget t;
@@ -1152,10 +1241,6 @@ void log_received_signal(int level, const struct signalfd_siginfo *si) {
}
-void log_set_upgrade_syslog_to_journal(bool b) {
- upgrade_syslog_to_journal = b;
-}
-
int log_syntax_internal(
const char *unit,
int level,
@@ -1189,7 +1274,7 @@ int log_syntax_internal(
va_end(ap);
if (unit)
- unit_fmt = getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s";
+ unit_fmt = getpid_cached() == 1 ? "UNIT=%s" : "USER_UNIT=%s";
return log_struct_internal(
LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
@@ -1203,6 +1288,14 @@ int log_syntax_internal(
NULL);
}
+void log_set_upgrade_syslog_to_journal(bool b) {
+ upgrade_syslog_to_journal = b;
+}
+
void log_set_always_reopen_console(bool b) {
always_reopen_console = b;
}
+
+void log_set_open_when_needed(bool b) {
+ open_when_needed = b;
+}
diff --git a/src/basic/log.h b/src/basic/log.h
index ff5d776b1d..10a6032788 100644
--- a/src/basic/log.h
+++ b/src/basic/log.h
@@ -30,6 +30,7 @@
#include "sd-id128.h"
#include "macro.h"
+#include "process-util.h"
typedef enum LogRealm {
LOG_REALM_SYSTEMD,
@@ -186,6 +187,15 @@ int log_format_iovec(
const char *format,
va_list ap) _printf_(6, 0);
+int log_struct_iovec_internal(
+ int level,
+ int error,
+ const char *file,
+ int line,
+ const char *func,
+ const struct iovec input_iovec[],
+ size_t n_input_iovec);
+
/* This modifies the buffer passed! */
int log_dump_internal(
int level,
@@ -247,7 +257,7 @@ void log_assert_failed_return_realm(
#define log_notice(...) log_full(LOG_NOTICE, __VA_ARGS__)
#define log_warning(...) log_full(LOG_WARNING, __VA_ARGS__)
#define log_error(...) log_full(LOG_ERR, __VA_ARGS__)
-#define log_emergency(...) log_full(getpid() == 1 ? LOG_EMERG : LOG_ERR, __VA_ARGS__)
+#define log_emergency(...) log_full(getpid_cached() == 1 ? LOG_EMERG : LOG_ERR, __VA_ARGS__)
/* Logging triggered by an errno-like error */
#define log_debug_errno(error, ...) log_full_errno(LOG_DEBUG, error, __VA_ARGS__)
@@ -255,7 +265,7 @@ void log_assert_failed_return_realm(
#define log_notice_errno(error, ...) log_full_errno(LOG_NOTICE, error, __VA_ARGS__)
#define log_warning_errno(error, ...) log_full_errno(LOG_WARNING, error, __VA_ARGS__)
#define log_error_errno(error, ...) log_full_errno(LOG_ERR, error, __VA_ARGS__)
-#define log_emergency_errno(error, ...) log_full_errno(getpid() == 1 ? LOG_EMERG : LOG_ERR, error, __VA_ARGS__)
+#define log_emergency_errno(error, ...) log_full_errno(getpid_cached() == 1 ? LOG_EMERG : LOG_ERR, error, __VA_ARGS__)
#ifdef LOG_TRACE
# define log_trace(...) log_debug(__VA_ARGS__)
@@ -269,6 +279,11 @@ void log_assert_failed_return_realm(
error, __FILE__, __LINE__, __func__, __VA_ARGS__)
#define log_struct(level, ...) log_struct_errno(level, 0, __VA_ARGS__)
+#define log_struct_iovec_errno(level, error, iovec, n_iovec) \
+ log_struct_iovec_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \
+ error, __FILE__, __LINE__, __func__, iovec, n_iovec)
+#define log_struct_iovec(level, iovec, n_iovec) log_struct_iovec_errno(level, 0, iovec, n_iovec)
+
/* This modifies the buffer passed! */
#define log_dump(level, buffer) \
log_dump_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \
@@ -288,6 +303,7 @@ void log_received_signal(int level, const struct signalfd_siginfo *si);
void log_set_upgrade_syslog_to_journal(bool b);
void log_set_always_reopen_console(bool b);
+void log_set_open_when_needed(bool b);
int log_syntax_internal(
const char *unit,
diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c
index 8c8cc78ebf..8f4f0e3a24 100644
--- a/src/basic/memfd-util.c
+++ b/src/basic/memfd-util.c
@@ -21,7 +21,7 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
-#ifdef HAVE_LINUX_MEMFD_H
+#if HAVE_LINUX_MEMFD_H
#include <linux/memfd.h>
#endif
#include <stdio.h>
diff --git a/src/basic/meson.build b/src/basic/meson.build
index 065f0ac4af..1ddefb7fbb 100644
--- a/src/basic/meson.build
+++ b/src/basic/meson.build
@@ -1,4 +1,6 @@
basic_sources_plain = files('''
+ MurmurHash2.c
+ MurmurHash2.h
af-list.c
af-list.h
alloc-util.c
@@ -16,6 +18,8 @@ basic_sources_plain = files('''
bitmap.c
bitmap.h
blkid-util.h
+ bpf-program.c
+ bpf-program.h
btrfs-ctree.h
btrfs-util.c
btrfs-util.h
@@ -24,10 +28,10 @@ basic_sources_plain = files('''
bus-label.h
calendarspec.c
calendarspec.h
- capability-util.c
- capability-util.h
cap-list.c
cap-list.h
+ capability-util.c
+ capability-util.h
cgroup-util.c
cgroup-util.h
chattr-util.c
@@ -61,10 +65,10 @@ basic_sources_plain = files('''
extract-word.h
fd-util.c
fd-util.h
- fileio.c
- fileio.h
fileio-label.c
fileio-label.h
+ fileio.c
+ fileio.h
format-util.h
fs-util.c
fs-util.h
@@ -82,9 +86,9 @@ basic_sources_plain = files('''
hostname-util.h
in-addr-util.c
in-addr-util.h
- ioprio.h
io-util.c
io-util.h
+ ioprio.h
journal-importer.c
journal-importer.h
khash.c
@@ -106,13 +110,11 @@ basic_sources_plain = files('''
mempool.c
mempool.h
missing_syscall.h
+ mkdir-label.c
mkdir.c
mkdir.h
- mkdir-label.c
mount-util.c
mount-util.h
- MurmurHash2.c
- MurmurHash2.h
nss-util.h
ordered-set.c
ordered-set.h
@@ -138,9 +140,12 @@ basic_sources_plain = files('''
rlimit-util.h
rm-rf.c
rm-rf.h
+ securebits-util.c
+ securebits-util.h
securebits.h
selinux-util.c
selinux-util.h
+ set.c
set.h
sigbus.c
sigbus.h
diff --git a/src/basic/missing.h b/src/basic/missing.h
index 7830a4f415..352d2b024b 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -40,7 +40,7 @@
#include <uchar.h>
#include <unistd.h>
-#ifdef HAVE_AUDIT
+#if HAVE_AUDIT
#include <libaudit.h>
#endif
@@ -48,11 +48,11 @@
#include <asm/sgidefs.h>
#endif
-#ifdef HAVE_LINUX_BTRFS_H
+#if HAVE_LINUX_BTRFS_H
#include <linux/btrfs.h>
#endif
-#ifdef HAVE_LINUX_VM_SOCKETS_H
+#if HAVE_LINUX_VM_SOCKETS_H
#include <linux/vm_sockets.h>
#else
#define VMADDR_CID_ANY -1U
@@ -204,7 +204,7 @@ struct sockaddr_vm {
#define BTRFS_QGROUP_LEVEL_SHIFT 48
#endif
-#ifndef HAVE_LINUX_BTRFS_H
+#if ! HAVE_LINUX_BTRFS_H
struct btrfs_ioctl_vol_args {
int64_t fd;
char name[BTRFS_PATH_NAME_MAX + 1];
@@ -546,8 +546,8 @@ struct btrfs_ioctl_quota_ctl_args {
#define MAX_HANDLE_SZ 128
#endif
-#ifndef HAVE_SECURE_GETENV
-# ifdef HAVE___SECURE_GETENV
+#if ! HAVE_SECURE_GETENV
+# if HAVE___SECURE_GETENV
# define secure_getenv __secure_getenv
# else
# error "neither secure_getenv nor __secure_getenv are available"
@@ -606,15 +606,14 @@ struct input_mask {
#else
#define __O_TMPFILE 020000000
#endif
+#endif
/* a horrid kludge trying to make sure that this will fail on old kernels */
#ifndef O_TMPFILE
#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
#endif
-#endif
-
-#if !HAVE_DECL_LO_FLAGS_PARTSCAN
+#if !HAVE_LO_FLAGS_PARTSCAN
#define LO_FLAGS_PARTSCAN 8
#endif
@@ -626,7 +625,7 @@ struct input_mask {
#define LOOP_CTL_GET_FREE 0x4C82
#endif
-#if !HAVE_DECL_IFLA_INET6_ADDR_GEN_MODE
+#if !HAVE_IFLA_INET6_ADDR_GEN_MODE
#define IFLA_INET6_UNSPEC 0
#define IFLA_INET6_FLAGS 1
#define IFLA_INET6_CONF 2
@@ -644,11 +643,11 @@ struct input_mask {
#define IN6_ADDR_GEN_MODE_NONE 1
#endif
-#if !HAVE_DECL_IN6_ADDR_GEN_MODE_STABLE_PRIVACY
+#if !HAVE_IN6_ADDR_GEN_MODE_STABLE_PRIVACY
#define IN6_ADDR_GEN_MODE_STABLE_PRIVACY 2
#endif
-#if !HAVE_DECL_IFLA_MACVLAN_FLAGS
+#if !HAVE_IFLA_MACVLAN_FLAGS
#define IFLA_MACVLAN_UNSPEC 0
#define IFLA_MACVLAN_MODE 1
#define IFLA_MACVLAN_FLAGS 2
@@ -657,7 +656,7 @@ struct input_mask {
#define IFLA_MACVLAN_MAX (__IFLA_MACVLAN_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_IPVLAN_MODE
+#if !HAVE_IFLA_IPVLAN_MODE
#define IFLA_IPVLAN_UNSPEC 0
#define IFLA_IPVLAN_MODE 1
#define __IFLA_IPVLAN_MAX 2
@@ -669,7 +668,7 @@ struct input_mask {
#define IPVLAN_MAX 2
#endif
-#if !HAVE_DECL_IFLA_VTI_REMOTE
+#if !HAVE_IFLA_VTI_REMOTE
#define IFLA_VTI_UNSPEC 0
#define IFLA_VTI_LINK 1
#define IFLA_VTI_IKEY 2
@@ -681,7 +680,7 @@ struct input_mask {
#define IFLA_VTI_MAX (__IFLA_VTI_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_PHYS_PORT_ID
+#if !HAVE_IFLA_PHYS_PORT_ID
#define IFLA_EXT_MASK 29
#undef IFLA_PROMISCUITY
#define IFLA_PROMISCUITY 30
@@ -694,7 +693,7 @@ struct input_mask {
#define IFLA_MAX (__IFLA_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_BOND_AD_INFO
+#if !HAVE_IFLA_BOND_AD_INFO
#define IFLA_BOND_UNSPEC 0
#define IFLA_BOND_MODE 1
#define IFLA_BOND_ACTIVE_SLAVE 2
@@ -724,7 +723,7 @@ struct input_mask {
#define IFLA_BOND_MAX (__IFLA_BOND_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_VLAN_PROTOCOL
+#if !HAVE_IFLA_VLAN_PROTOCOL
#define IFLA_VLAN_UNSPEC 0
#define IFLA_VLAN_ID 1
#define IFLA_VLAN_FLAGS 2
@@ -736,7 +735,7 @@ struct input_mask {
#define IFLA_VLAN_MAX (__IFLA_VLAN_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_VXLAN_GPE
+#if !HAVE_IFLA_VXLAN_GPE
#define IFLA_VXLAN_UNSPEC 0
#define IFLA_VXLAN_ID 1
#define IFLA_VXLAN_GROUP 2
@@ -771,7 +770,7 @@ struct input_mask {
#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_GENEVE_LABEL
+#if !HAVE_IFLA_GENEVE_LABEL
#define IFLA_GENEVE_UNSPEC 0
#define IFLA_GENEVE_ID 1
#define IFLA_GENEVE_REMOTE 2
@@ -790,7 +789,7 @@ struct input_mask {
#define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_IPTUN_ENCAP_DPORT
+#if !HAVE_IFLA_IPTUN_ENCAP_DPORT
#define IFLA_IPTUN_UNSPEC 0
#define IFLA_IPTUN_LINK 1
#define IFLA_IPTUN_LOCAL 2
@@ -816,7 +815,7 @@ struct input_mask {
#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_GRE_ENCAP_DPORT
+#if !HAVE_IFLA_GRE_ENCAP_DPORT
#define IFLA_GRE_UNSPEC 0
#define IFLA_GRE_LINK 1
#define IFLA_GRE_IFLAGS 2
@@ -841,7 +840,7 @@ struct input_mask {
#define IFLA_GRE_MAX (__IFLA_GRE_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_BRIDGE_VLAN_INFO
+#if !HAVE_IFLA_BRIDGE_VLAN_INFO
#define IFLA_BRIDGE_FLAGS 0
#define IFLA_BRIDGE_MODE 1
#define IFLA_BRIDGE_VLAN_INFO 2
@@ -858,7 +857,7 @@ struct input_mask {
#define BRIDGE_VLAN_INFO_RANGE_END (1<<4) /* VLAN is end of vlan range */
#endif
-#if !HAVE_DECL_IFLA_BR_VLAN_DEFAULT_PVID
+#if !HAVE_IFLA_BR_VLAN_DEFAULT_PVID
#define IFLA_BR_UNSPEC 0
#define IFLA_BR_FORWARD_DELAY 1
#define IFLA_BR_HELLO_TIME 2
@@ -904,7 +903,7 @@ struct input_mask {
#define IFLA_BR_MAX (__IFLA_BR_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_BRPORT_LEARNING_SYNC
+#if !HAVE_IFLA_BRPORT_LEARNING_SYNC
#define IFLA_BRPORT_UNSPEC 0
#define IFLA_BRPORT_STATE 1
#define IFLA_BRPORT_PRIORITY 2
@@ -921,15 +920,42 @@ struct input_mask {
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_BRPORT_PROXYARP
+#if !HAVE_FRA_UID_RANGE
+#define FRA_UNSPEC 0
+#define FRA_DST 1
+#define FRA_SRC 2
+#define FRA_IIFNAME 3
+#define FRA_GOTO 4
+#define FRA_UNUSED2 5
+#define FRA_PRIORITY 6
+#define FRA_UNUSED3 7
+#define FRA_UNUSED4 8
+#define FRA_UNUSED5 9
+#define FRA_FWMARK 10
+#define FRA_FLOW 11
+#define FRA_TUN_ID 12
+#define FRA_SUPPRESS_IFGROUP 13
+#define FRA_SUPPRESS_PREFIXLEN 14
+#define FRA_TABLE 15
+#define FRA_FWMASK 16
+#define FRA_OIFNAME 17
+#define FRA_PAD 18
+#define FRA_L3MDEV 19
+#define FRA_UID_RANGE 20
+#define __FRA_MAX 12
+
+#define FRA_MAX (__FRA_MAX - 1)
+#endif
+
+#if !HAVE_IFLA_BRPORT_PROXYARP
#define IFLA_BRPORT_PROXYARP 10
#endif
-#if !HAVE_DECL_IFLA_VRF_TABLE
+#if !HAVE_IFLA_VRF_TABLE
#define IFLA_VRF_TABLE 1
#endif
-#if !HAVE_DECL_NDA_IFINDEX
+#if !HAVE_NDA_IFINDEX
#define NDA_UNSPEC 0
#define NDA_DST 1
#define NDA_LLADDR 2
@@ -1013,7 +1039,7 @@ struct input_mask {
#define LOOPBACK_IFINDEX 1
#endif
-#if !HAVE_DECL_IFA_FLAGS
+#if !HAVE_IFA_FLAGS
#define IFA_FLAGS 8
#endif
@@ -1082,7 +1108,7 @@ struct input_mask {
#define KEY_ALS_TOGGLE 0x230
#endif
-#ifndef HAVE_KEY_SERIAL_T
+#if ! HAVE_KEY_SERIAL_T
typedef int32_t key_serial_t;
#endif
@@ -1102,6 +1128,10 @@ typedef int32_t key_serial_t;
#define KEYCTL_DESCRIBE 6
#endif
+#ifndef KEYCTL_LINK
+#define KEYCTL_LINK 8
+#endif
+
#ifndef KEYCTL_READ
#define KEYCTL_READ 11
#endif
@@ -1174,11 +1204,11 @@ typedef int32_t key_serial_t;
#ifndef IF_OPER_UP
#define IF_OPER_UP 6
-#ifndef HAVE_CHAR32_T
+#if ! HAVE_CHAR32_T
#define char32_t uint32_t
#endif
-#ifndef HAVE_CHAR16_T
+#if ! HAVE_CHAR16_T
#define char16_t uint16_t
#endif
@@ -1190,7 +1220,7 @@ typedef int32_t key_serial_t;
#define IFA_F_MCAUTOJOIN 0x400
#endif
-#ifndef HAVE_STRUCT_ETHTOOL_LINK_SETTINGS
+#if ! HAVE_STRUCT_ETHTOOL_LINK_SETTINGS
#define ETHTOOL_GLINKSETTINGS 0x0000004c /* Get ethtool_link_settings */
#define ETHTOOL_SLINKSETTINGS 0x0000004d /* Set ethtool_link_settings */
@@ -1217,6 +1247,15 @@ struct ethtool_link_settings {
#endif
+#if ! HAVE_STRUCT_FIB_RULE_UID_RANGE
+
+struct fib_rule_uid_range {
+ __u32 start;
+ __u32 end;
+};
+
+#endif
+
#endif
#ifndef SOL_ALG
diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h
index 898116c7b3..3322e4e4d6 100644
--- a/src/basic/missing_syscall.h
+++ b/src/basic/missing_syscall.h
@@ -22,7 +22,9 @@
/* Missing glibc definitions to access certain kernel APIs */
-#if !HAVE_DECL_PIVOT_ROOT
+#include <sys/types.h>
+
+#if !HAVE_PIVOT_ROOT
static inline int pivot_root(const char *new_root, const char *put_old) {
return syscall(SYS_pivot_root, new_root, put_old);
}
@@ -30,7 +32,7 @@ static inline int pivot_root(const char *new_root, const char *put_old) {
/* ======================================================================= */
-#if !HAVE_DECL_MEMFD_CREATE
+#if !HAVE_MEMFD_CREATE
# ifndef __NR_memfd_create
# if defined __x86_64__
# define __NR_memfd_create 319
@@ -71,7 +73,7 @@ static inline int memfd_create(const char *name, unsigned int flags) {
/* ======================================================================= */
-#if !HAVE_DECL_GETRANDOM
+#if !HAVE_GETRANDOM
# ifndef __NR_getrandom
# if defined __x86_64__
# define __NR_getrandom 318
@@ -118,7 +120,7 @@ static inline int getrandom(void *buffer, size_t count, unsigned flags) {
/* ======================================================================= */
-#if !HAVE_DECL_GETTID
+#if !HAVE_GETTID
static inline pid_t gettid(void) {
return (pid_t) syscall(SYS_gettid);
}
@@ -126,7 +128,7 @@ static inline pid_t gettid(void) {
/* ======================================================================= */
-#if !HAVE_DECL_NAME_TO_HANDLE_AT
+#if !HAVE_NAME_TO_HANDLE_AT
# ifndef __NR_name_to_handle_at
# if defined(__x86_64__)
# define __NR_name_to_handle_at 303
@@ -161,7 +163,7 @@ static inline int name_to_handle_at(int fd, const char *name, struct file_handle
/* ======================================================================= */
-#if !HAVE_DECL_SETNS
+#if !HAVE_SETNS
# ifndef __NR_setns
# if defined(__x86_64__)
# define __NR_setns 308
@@ -196,7 +198,7 @@ static inline pid_t raw_getpid(void) {
/* ======================================================================= */
-#if !HAVE_DECL_RENAMEAT2
+#if !HAVE_RENAMEAT2
# ifndef __NR_renameat2
# if defined __x86_64__
# define __NR_renameat2 316
@@ -239,7 +241,7 @@ static inline int renameat2(int oldfd, const char *oldname, int newfd, const cha
/* ======================================================================= */
-#if !HAVE_DECL_KCMP
+#if !HAVE_KCMP
static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) {
# ifdef __NR_kcmp
return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2);
@@ -252,7 +254,7 @@ static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, uns
/* ======================================================================= */
-#if !HAVE_DECL_KEYCTL
+#if !HAVE_KEYCTL
static inline long keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4,unsigned long arg5) {
# ifdef __NR_keyctl
return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5);
@@ -283,7 +285,7 @@ static inline key_serial_t request_key(const char *type, const char *description
/* ======================================================================= */
-#if !HAVE_DECL_COPY_FILE_RANGE
+#if !HAVE_COPY_FILE_RANGE
# ifndef __NR_copy_file_range
# if defined(__x86_64__)
# define __NR_copy_file_range 326
@@ -316,3 +318,33 @@ static inline ssize_t copy_file_range(int fd_in, loff_t *off_in,
# endif
}
#endif
+
+#if !HAVE_BPF
+# ifndef __NR_bpf
+# if defined __i386__
+# define __NR_bpf 357
+# elif defined __x86_64__
+# define __NR_bpf 321
+# elif defined __aarch64__
+# define __NR_bpf 280
+# elif defined __sparc__
+# define __NR_bpf 349
+# elif defined __s390__
+# define __NR_bpf 351
+# else
+# warning "__NR_bpf not defined for your architecture"
+# endif
+# endif
+
+union bpf_attr;
+
+static inline int bpf(int cmd, union bpf_attr *attr, size_t size) {
+#ifdef __NR_bpf
+ return (int) syscall(__NR_bpf, cmd, attr, size);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+#endif
diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c
index 6b1a98402c..7db09fc6a1 100644
--- a/src/basic/mkdir.c
+++ b/src/basic/mkdir.c
@@ -31,10 +31,13 @@
int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkdir_func_t _mkdir) {
struct stat st;
+ int r;
- if (_mkdir(path, mode) >= 0)
- if (chmod_and_chown(path, mode, uid, gid) < 0)
- return -errno;
+ if (_mkdir(path, mode) >= 0) {
+ r = chmod_and_chown(path, mode, uid, gid);
+ if (r < 0)
+ return r;
+ }
if (lstat(path, &st) < 0)
return -errno;
diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c
index 7b9400b47c..c4d451db73 100644
--- a/src/basic/mount-util.c
+++ b/src/basic/mount-util.c
@@ -472,14 +472,14 @@ int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **bl
while ((x = set_steal_first(todo))) {
r = set_consume(done, x);
- if (r == -EEXIST || r == 0)
+ if (IN_SET(r, 0, -EEXIST))
continue;
if (r < 0)
return r;
/* Deal with mount points that are obstructed by a later mount */
r = path_is_mount_point(x, NULL, 0);
- if (r == -ENOENT || r == 0)
+ if (IN_SET(r, 0, -ENOENT))
continue;
if (r < 0)
return r;
@@ -526,30 +526,67 @@ int mount_move_root(const char *path) {
}
bool fstype_is_network(const char *fstype) {
- static const char table[] =
- "afs\0"
- "cifs\0"
- "smbfs\0"
- "sshfs\0"
- "ncpfs\0"
- "ncp\0"
- "nfs\0"
- "nfs4\0"
- "gfs\0"
- "gfs2\0"
- "glusterfs\0"
- "pvfs2\0" /* OrangeFS */
- "ocfs2\0"
- "lustre\0"
- ;
-
const char *x;
x = startswith(fstype, "fuse.");
if (x)
fstype = x;
- return nulstr_contains(table, fstype);
+ return STR_IN_SET(fstype,
+ "afs",
+ "cifs",
+ "smbfs",
+ "sshfs",
+ "ncpfs",
+ "ncp",
+ "nfs",
+ "nfs4",
+ "gfs",
+ "gfs2",
+ "glusterfs",
+ "pvfs2", /* OrangeFS */
+ "ocfs2",
+ "lustre");
+}
+
+bool fstype_is_api_vfs(const char *fstype) {
+ return STR_IN_SET(fstype,
+ "autofs",
+ "bpf",
+ "cgroup",
+ "cgroup2",
+ "configfs",
+ "cpuset",
+ "debugfs",
+ "devpts",
+ "devtmpfs",
+ "efivarfs",
+ "fusectl",
+ "hugetlbfs",
+ "mqueue",
+ "proc",
+ "pstore",
+ "ramfs",
+ "securityfs",
+ "sysfs",
+ "tmpfs",
+ "tracefs");
+}
+
+bool fstype_is_ro(const char *fstype) {
+ /* All Linux file systems that are necessarily read-only */
+ return STR_IN_SET(fstype,
+ "DM_verity_hash",
+ "iso9660",
+ "squashfs");
+}
+
+bool fstype_can_discard(const char *fstype) {
+ return STR_IN_SET(fstype,
+ "btrfs",
+ "ext4",
+ "vfat",
+ "xfs");
}
int repeat_unmount(const char *path, int flags) {
diff --git a/src/basic/mount-util.h b/src/basic/mount-util.h
index 2e24a184c5..1e066d8886 100644
--- a/src/basic/mount-util.h
+++ b/src/basic/mount-util.h
@@ -44,6 +44,9 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent);
#define _cleanup_endmntent_ _cleanup_(endmntentp)
bool fstype_is_network(const char *fstype);
+bool fstype_is_api_vfs(const char *fstype);
+bool fstype_is_ro(const char *fsype);
+bool fstype_can_discard(const char *fstype);
union file_handle_union {
struct file_handle handle;
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index 4532f222c8..4ae07b0a8e 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -59,7 +59,7 @@ int parse_pid(const char *s, pid_t* ret_pid) {
if ((unsigned long) pid != ul)
return -ERANGE;
- if (pid <= 0)
+ if (!pid_is_valid(pid))
return -ERANGE;
*ret_pid = pid;
@@ -152,7 +152,7 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) {
unsigned n_entries, start_pos = 0;
assert(t);
- assert(base == 1000 || base == 1024);
+ assert(IN_SET(base, 1000, 1024));
assert(size);
if (base == 1000) {
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index 80fdda170f..6c06bd2acb 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -131,8 +131,7 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
/* Skip the common part. */
for (;;) {
- size_t a;
- size_t b;
+ size_t a, b;
from_dir += strspn(from_dir, "/");
to_path += strspn(to_path, "/");
@@ -144,7 +143,6 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
else
/* from_dir is a parent directory of to_path. */
r = strdup(to_path);
-
if (!r)
return -ENOMEM;
@@ -175,21 +173,32 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
/* Count the number of necessary ".." elements. */
for (n_parents = 0;;) {
+ size_t w;
+
from_dir += strspn(from_dir, "/");
if (!*from_dir)
break;
- from_dir += strcspn(from_dir, "/");
- n_parents++;
+ w = strcspn(from_dir, "/");
+
+ /* If this includes ".." we can't do a simple series of "..", refuse */
+ if (w == 2 && from_dir[0] == '.' && from_dir[1] == '.')
+ return -EINVAL;
+
+ /* Count number of elements, except if they are "." */
+ if (w != 1 || from_dir[0] != '.')
+ n_parents++;
+
+ from_dir += w;
}
- r = malloc(n_parents * 3 + strlen(to_path) + 1);
+ r = new(char, n_parents * 3 + strlen(to_path) + 1);
if (!r)
return -ENOMEM;
- for (p = r; n_parents > 0; n_parents--, p += 3)
- memcpy(p, "../", 3);
+ for (p = r; n_parents > 0; n_parents--)
+ p = mempcpy(p, "../", 3);
strcpy(p, to_path);
path_kill_slashes(r);
diff --git a/src/basic/path-util.h b/src/basic/path-util.h
index 26f165fc38..546246595c 100644
--- a/src/basic/path-util.h
+++ b/src/basic/path-util.h
@@ -30,7 +30,7 @@
#define DEFAULT_PATH_NORMAL "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
#define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":/sbin:/bin"
-#ifdef HAVE_SPLIT_USR
+#if HAVE_SPLIT_USR
# define DEFAULT_PATH DEFAULT_PATH_SPLIT_USR
#else
# define DEFAULT_PATH DEFAULT_PATH_NORMAL
@@ -143,3 +143,13 @@ bool is_deviceallow_pattern(const char *path);
int systemd_installation_has_version(const char *root, unsigned minimal_version);
bool dot_or_dot_dot(const char *path);
+
+static inline const char *skip_dev_prefix(const char *p) {
+ const char *e;
+
+ /* Drop any /dev prefix if there is any */
+
+ e = path_startswith(p, "/dev/");
+
+ return e ?: p;
+}
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index b80cacaa42..99b0946a03 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -34,7 +34,7 @@
#include <sys/wait.h>
#include <syslog.h>
#include <unistd.h>
-#ifdef HAVE_VALGRIND_VALGRIND_H
+#if HAVE_VALGRIND_VALGRIND_H
#include <valgrind/valgrind.h>
#endif
@@ -312,19 +312,18 @@ int rename_process(const char name[]) {
/* Third step, completely replace the argv[] array the kernel maintains for us. This requires privileges, but
* has the advantage that the argv[] array is exactly what we want it to be, and not filled up with zeros at
* the end. This is the best option for changing /proc/self/cmdline. */
- if (mm_size < l+1) {
+
+ /* Let's not bother with this if we don't have euid == 0. Strictly speaking we should check for the
+ * CAP_SYS_RESOURCE capability which is independent of the euid. In our own code the capability generally is
+ * present only for euid == 0, hence let's use this as quick bypass check, to avoid calling mmap() if
+ * PR_SET_MM_ARG_{START,END} fails with EPERM later on anyway. After all geteuid() is dead cheap to call, but
+ * mmap() is not. */
+ if (geteuid() != 0)
+ log_debug("Skipping PR_SET_MM, as we don't have privileges.");
+ else if (mm_size < l+1) {
size_t nn_size;
char *nn;
- /* Let's not bother with this if we don't have euid == 0. Strictly speaking if people do weird stuff
- * with capabilities this could work even for euid != 0, but our own code generally doesn't do that,
- * hence let's use this as quick bypass check, to avoid calling mmap() if PR_SET_MM_ARG_START fails
- * with EPERM later on anyway. After all geteuid() is dead cheap to call, but mmap() is not. */
- if (geteuid() != 0) {
- log_debug("Skipping PR_SET_MM_ARG_START, as we don't have privileges.");
- goto use_saved_argv;
- }
-
nn_size = PAGE_ALIGN(l+1);
nn = mmap(NULL, nn_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (nn == MAP_FAILED) {
@@ -351,9 +350,14 @@ int rename_process(const char name[]) {
mm = nn;
mm_size = nn_size;
- } else
+ } else {
strncpy(mm, name, mm_size);
+ /* Update the end pointer, continuing regardless of any failure. */
+ if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) mm + l + 1, 0, 0) < 0)
+ log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m");
+ }
+
use_saved_argv:
/* Fourth step: in all cases we'll also update the original argv[], so that our own code gets it right too if
* it still looks here */
@@ -388,7 +392,7 @@ int is_kernel_thread(pid_t pid) {
bool eof;
FILE *f;
- if (pid == 0 || pid == 1) /* pid 1, and we ourselves certainly aren't a kernel thread */
+ if (IN_SET(pid, 0, 1) || pid == getpid_cached()) /* pid 1, and we ourselves certainly aren't a kernel thread */
return 0;
assert(pid > 1);
@@ -471,6 +475,9 @@ static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
assert(field);
assert(uid);
+ if (pid < 0)
+ return -EINVAL;
+
p = procfs_file_alloca(pid, "status");
f = fopen(p, "re");
if (!f) {
@@ -498,10 +505,22 @@ static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
}
int get_process_uid(pid_t pid, uid_t *uid) {
+
+ if (pid == 0 || pid == getpid_cached()) {
+ *uid = getuid();
+ return 0;
+ }
+
return get_process_id(pid, "Uid:", uid);
}
int get_process_gid(pid_t pid, gid_t *gid) {
+
+ if (pid == 0 || pid == getpid_cached()) {
+ *gid = getgid();
+ return 0;
+ }
+
assert_cc(sizeof(uid_t) == sizeof(gid_t));
return get_process_id(pid, "Gid:", gid);
}
@@ -577,7 +596,7 @@ int get_process_ppid(pid_t pid, pid_t *_ppid) {
assert(pid >= 0);
assert(_ppid);
- if (pid == 0) {
+ if (pid == 0 || pid == getpid_cached()) {
*_ppid = getppid();
return 0;
}
@@ -669,8 +688,7 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_cod
log_debug("%s succeeded.", name);
return status.si_status;
- } else if (status.si_code == CLD_KILLED ||
- status.si_code == CLD_DUMPED) {
+ } else if (IN_SET(status.si_code, CLD_KILLED, CLD_DUMPED)) {
log_warning("%s terminated by signal %s.", name, signal_to_string(status.si_status));
return -EPROTO;
@@ -775,6 +793,9 @@ bool pid_is_unwaited(pid_t pid) {
if (pid <= 1) /* If we or PID 1 would be dead and have been waited for, this code would not be running */
return true;
+ if (pid == getpid_cached())
+ return true;
+
if (kill(pid, 0) >= 0)
return true;
@@ -792,8 +813,11 @@ bool pid_is_alive(pid_t pid) {
if (pid <= 1) /* If we or PID 1 would be a zombie, this code would not be running */
return true;
+ if (pid == getpid_cached())
+ return true;
+
r = get_process_state(pid);
- if (r == -ESRCH || r == 'Z')
+ if (IN_SET(r, -ESRCH, 'Z'))
return false;
return true;
@@ -803,7 +827,10 @@ int pid_from_same_root_fs(pid_t pid) {
const char *root;
if (pid < 0)
- return 0;
+ return false;
+
+ if (pid == 0 || pid == getpid_cached())
+ return true;
root = procfs_file_alloca(pid, "root");
@@ -814,7 +841,7 @@ bool is_main_thread(void) {
static thread_local int cached = 0;
if (_unlikely_(cached == 0))
- cached = getpid() == gettid() ? 1 : -1;
+ cached = getpid_cached() == gettid() ? 1 : -1;
return cached > 0;
}
@@ -876,9 +903,50 @@ const char* personality_to_string(unsigned long p) {
return architecture_to_string(architecture);
}
+int safe_personality(unsigned long p) {
+ int ret;
+
+ /* So here's the deal, personality() is weirdly defined by glibc. In some cases it returns a failure via errno,
+ * and in others as negative return value containing an errno-like value. Let's work around this: this is a
+ * wrapper that uses errno if it is set, and uses the return value otherwise. And then it sets both errno and
+ * the return value indicating the same issue, so that we are definitely on the safe side.
+ *
+ * See https://github.com/systemd/systemd/issues/6737 */
+
+ errno = 0;
+ ret = personality(p);
+ if (ret < 0) {
+ if (errno != 0)
+ return -errno;
+
+ errno = -ret;
+ }
+
+ return ret;
+}
+
+int opinionated_personality(unsigned long *ret) {
+ int current;
+
+ /* Returns the current personality, or PERSONALITY_INVALID if we can't determine it. This function is a bit
+ * opinionated though, and ignores all the finer-grained bits and exotic personalities, only distinguishing the
+ * two most relevant personalities: PER_LINUX and PER_LINUX32. */
+
+ current = safe_personality(PERSONALITY_INVALID);
+ if (current < 0)
+ return current;
+
+ if (((unsigned long) current & 0xffff) == PER_LINUX32)
+ *ret = PER_LINUX32;
+ else
+ *ret = PER_LINUX;
+
+ return 0;
+}
+
void valgrind_summary_hack(void) {
-#ifdef HAVE_VALGRIND_VALGRIND_H
- if (getpid() == 1 && RUNNING_ON_VALGRIND) {
+#if HAVE_VALGRIND_VALGRIND_H
+ if (getpid_cached() == 1 && RUNNING_ON_VALGRIND) {
pid_t pid;
pid = raw_clone(SIGCHLD);
if (pid < 0)
@@ -922,6 +990,68 @@ int ioprio_parse_priority(const char *s, int *ret) {
return 0;
}
+/* The cached PID, possible values:
+ *
+ * == UNSET [0] → cache not initialized yet
+ * == BUSY [-1] → some thread is initializing it at the moment
+ * any other → the cached PID
+ */
+
+#define CACHED_PID_UNSET ((pid_t) 0)
+#define CACHED_PID_BUSY ((pid_t) -1)
+
+static pid_t cached_pid = CACHED_PID_UNSET;
+
+static void reset_cached_pid(void) {
+ /* Invoked in the child after a fork(), i.e. at the first moment the PID changed */
+ cached_pid = CACHED_PID_UNSET;
+}
+
+/* We use glibc __register_atfork() + __dso_handle directly here, as they are not included in the glibc
+ * headers. __register_atfork() is mostly equivalent to pthread_atfork(), but doesn't require us to link against
+ * libpthread, as it is part of glibc anyway. */
+extern int __register_atfork(void (*prepare) (void), void (*parent) (void), void (*child) (void), void * __dso_handle);
+extern void* __dso_handle __attribute__ ((__weak__));
+
+pid_t getpid_cached(void) {
+ pid_t current_value;
+
+ /* getpid_cached() is much like getpid(), but caches the value in local memory, to avoid having to invoke a
+ * system call each time. This restores glibc behaviour from before 2.24, when getpid() was unconditionally
+ * cached. Starting with 2.24 getpid() started to become prohibitively expensive when used for detecting when
+ * objects were used across fork()s. With this caching the old behaviour is somewhat restored.
+ *
+ * https://bugzilla.redhat.com/show_bug.cgi?id=1443976
+ * https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=c579f48edba88380635ab98cb612030e3ed8691e
+ */
+
+ current_value = __sync_val_compare_and_swap(&cached_pid, CACHED_PID_UNSET, CACHED_PID_BUSY);
+
+ switch (current_value) {
+
+ case CACHED_PID_UNSET: { /* Not initialized yet, then do so now */
+ pid_t new_pid;
+
+ new_pid = getpid();
+
+ if (__register_atfork(NULL, NULL, reset_cached_pid, __dso_handle) != 0) {
+ /* OOM? Let's try again later */
+ cached_pid = CACHED_PID_UNSET;
+ return new_pid;
+ }
+
+ cached_pid = new_pid;
+ return new_pid;
+ }
+
+ case CACHED_PID_BUSY: /* Somebody else is currently initializing */
+ return getpid();
+
+ default: /* Properly initialized */
+ return current_value;
+ }
+}
+
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",
diff --git a/src/basic/process-util.h b/src/basic/process-util.h
index 28d8d7499a..82af2f9181 100644
--- a/src/basic/process-util.h
+++ b/src/basic/process-util.h
@@ -20,6 +20,7 @@
***/
#include <alloca.h>
+#include <sched.h>
#include <signal.h>
#include <stdbool.h>
#include <stddef.h>
@@ -90,6 +91,9 @@ bool oom_score_adjust_is_valid(int oa);
unsigned long personality_from_string(const char *p);
const char *personality_to_string(unsigned long);
+int safe_personality(unsigned long p);
+int opinionated_personality(unsigned long *ret);
+
int ioprio_class_to_string_alloc(int i, char **s);
int ioprio_class_from_string(const char *s);
@@ -110,6 +114,14 @@ static inline bool nice_is_valid(int n) {
return n >= PRIO_MIN && n < PRIO_MAX;
}
+static inline bool sched_policy_is_valid(int i) {
+ return IN_SET(i, SCHED_OTHER, SCHED_BATCH, SCHED_IDLE, SCHED_FIFO, SCHED_RR);
+}
+
+static inline bool sched_priority_is_valid(int i) {
+ return i >= 0 && i <= sched_get_priority_max(SCHED_RR);
+}
+
static inline bool ioprio_class_is_valid(int i) {
return IN_SET(i, IOPRIO_CLASS_NONE, IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE);
}
@@ -118,4 +130,10 @@ static inline bool ioprio_priority_is_valid(int i) {
return i >= 0 && i < IOPRIO_BE_NR;
}
+static inline bool pid_is_valid(pid_t p) {
+ return p > 0;
+}
+
int ioprio_parse_priority(const char *s, int *ret);
+
+pid_t getpid_cached(void);
diff --git a/src/basic/random-util.c b/src/basic/random-util.c
index 810eeab4d5..146c8f55ed 100644
--- a/src/basic/random-util.c
+++ b/src/basic/random-util.c
@@ -26,11 +26,11 @@
#include <linux/random.h>
#include <stdint.h>
-#ifdef HAVE_SYS_AUXV_H
+#if HAVE_SYS_AUXV_H
# include <sys/auxv.h>
#endif
-#ifdef USE_SYS_RANDOM_H
+#if USE_SYS_RANDOM_H
# include <sys/random.h>
#else
# include <linux/random.h>
@@ -64,7 +64,7 @@ int acquire_random_bytes(void *p, size_t n, bool high_quality_required) {
if ((size_t) r == n)
return 0;
if (!high_quality_required) {
- /* Fill in the remaing bytes using pseudorandom values */
+ /* Fill in the remaining bytes using pseudorandom values */
pseudorandom_bytes((uint8_t*) p + r, n - r);
return 0;
}
@@ -100,14 +100,14 @@ int acquire_random_bytes(void *p, size_t n, bool high_quality_required) {
void initialize_srand(void) {
static bool srand_called = false;
unsigned x;
-#ifdef HAVE_SYS_AUXV_H
+#if HAVE_SYS_AUXV_H
void *auxv;
#endif
if (srand_called)
return;
-#ifdef HAVE_SYS_AUXV_H
+#if HAVE_SYS_AUXV_H
/* The kernel provides us with 16 bytes of entropy in auxv, so let's
* try to make use of that to seed the pseudo-random generator. It's
* better than nothing... */
diff --git a/src/basic/replace-var.c b/src/basic/replace-var.c
index 0d21423a9c..d2642812e7 100644
--- a/src/basic/replace-var.c
+++ b/src/basic/replace-var.c
@@ -54,7 +54,7 @@ static int get_variable(const char *b, char **r) {
return 1;
}
-char *replace_var(const char *text, char *(*lookup)(const char *variable, void*userdata), void *userdata) {
+char *replace_var(const char *text, char *(*lookup)(const char *variable, void *userdata), void *userdata) {
char *r, *t;
const char *f;
size_t l;
diff --git a/src/basic/replace-var.h b/src/basic/replace-var.h
index 78412910b2..31eb057803 100644
--- a/src/basic/replace-var.h
+++ b/src/basic/replace-var.h
@@ -19,4 +19,4 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-char *replace_var(const char *text, char *(*lookup)(const char *variable, void*userdata), void *userdata);
+char *replace_var(const char *text, char *(*lookup)(const char *variable, void *userdata), void *userdata);
diff --git a/src/basic/rlimit-util.c b/src/basic/rlimit-util.c
index ca834df621..5c41429f01 100644
--- a/src/basic/rlimit-util.c
+++ b/src/basic/rlimit-util.c
@@ -42,7 +42,8 @@ int setrlimit_closest(int resource, const struct rlimit *rlim) {
/* So we failed to set the desired setrlimit, then let's try
* to get as close as we can */
- assert_se(getrlimit(resource, &highest) == 0);
+ if (getrlimit(resource, &highest) < 0)
+ return -errno;
fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max);
fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max);
diff --git a/src/basic/rm-rf.c b/src/basic/rm-rf.c
index 3f80ed263a..0bbafb4cd7 100644
--- a/src/basic/rm-rf.c
+++ b/src/basic/rm-rf.c
@@ -132,7 +132,7 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
r = btrfs_subvol_remove_fd(fd, de->d_name, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
if (r < 0) {
- if (r != -ENOTTY && r != -EINVAL) {
+ if (!IN_SET(r, -ENOTTY, -EINVAL)) {
if (ret == 0)
ret = r;
@@ -193,7 +193,7 @@ int rm_rf(const char *path, RemoveFlags flags) {
if (r >= 0)
return r;
- if (r != -ENOTTY && r != -EINVAL && r != -ENOTDIR)
+ if (!IN_SET(r, -ENOTTY, -EINVAL, -ENOTDIR))
return r;
/* Not btrfs or not a subvolume */
@@ -202,7 +202,7 @@ int rm_rf(const char *path, RemoveFlags flags) {
fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
if (fd < 0) {
- if (errno != ENOTDIR && errno != ELOOP)
+ if (!IN_SET(errno, ENOTDIR, ELOOP))
return -errno;
if (!(flags & REMOVE_PHYSICAL)) {
diff --git a/src/basic/securebits-util.c b/src/basic/securebits-util.c
new file mode 100644
index 0000000000..011ec36af4
--- /dev/null
+++ b/src/basic/securebits-util.c
@@ -0,0 +1,84 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2017 Yu Watanabe
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+
+#include "alloc-util.h"
+#include "extract-word.h"
+#include "securebits.h"
+#include "securebits-util.h"
+#include "string-util.h"
+
+int secure_bits_to_string_alloc(int i, char **s) {
+ _cleanup_free_ char *str = NULL;
+ size_t len;
+ int r;
+
+ assert(s);
+
+ r = asprintf(&str, "%s%s%s%s%s%s",
+ (i & (1 << SECURE_KEEP_CAPS)) ? "keep-caps " : "",
+ (i & (1 << SECURE_KEEP_CAPS_LOCKED)) ? "keep-caps-locked " : "",
+ (i & (1 << SECURE_NO_SETUID_FIXUP)) ? "no-setuid-fixup " : "",
+ (i & (1 << SECURE_NO_SETUID_FIXUP_LOCKED)) ? "no-setuid-fixup-locked " : "",
+ (i & (1 << SECURE_NOROOT)) ? "noroot " : "",
+ (i & (1 << SECURE_NOROOT_LOCKED)) ? "noroot-locked " : "");
+ if (r < 0)
+ return -ENOMEM;
+
+ len = strlen(str);
+ if (len != 0)
+ str[len - 1] = '\0';
+
+ *s = str;
+ str = NULL;
+
+ return 0;
+}
+
+int secure_bits_from_string(const char *s) {
+ int secure_bits = 0;
+ const char *p;
+ int r;
+
+ for (p = s;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+ if (r == -ENOMEM)
+ return r;
+ if (r <= 0)
+ break;
+
+ if (streq(word, "keep-caps"))
+ secure_bits |= 1 << SECURE_KEEP_CAPS;
+ else if (streq(word, "keep-caps-locked"))
+ secure_bits |= 1 << SECURE_KEEP_CAPS_LOCKED;
+ else if (streq(word, "no-setuid-fixup"))
+ secure_bits |= 1 << SECURE_NO_SETUID_FIXUP;
+ else if (streq(word, "no-setuid-fixup-locked"))
+ secure_bits |= 1 << SECURE_NO_SETUID_FIXUP_LOCKED;
+ else if (streq(word, "noroot"))
+ secure_bits |= 1 << SECURE_NOROOT;
+ else if (streq(word, "noroot-locked"))
+ secure_bits |= 1 << SECURE_NOROOT_LOCKED;
+ }
+
+ return secure_bits;
+}
diff --git a/src/basic/securebits-util.h b/src/basic/securebits-util.h
new file mode 100644
index 0000000000..b4d970c366
--- /dev/null
+++ b/src/basic/securebits-util.h
@@ -0,0 +1,28 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2017 Yu Watanabe
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "securebits.h"
+
+int secure_bits_to_string_alloc(int i, char **s);
+int secure_bits_from_string(const char *s);
+static inline bool secure_bits_is_valid(int i) {
+ return ((SECURE_ALL_BITS | SECURE_ALL_LOCKS) & i) == i;
+}
diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c
index 139e6e21e3..93bcdb2160 100644
--- a/src/basic/selinux-util.c
+++ b/src/basic/selinux-util.c
@@ -26,7 +26,7 @@
#include <sys/un.h>
#include <syslog.h>
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
#include <selinux/context.h>
#include <selinux/label.h>
#include <selinux/selinux.h>
@@ -40,7 +40,7 @@
#include "time-util.h"
#include "util.h"
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
DEFINE_TRIVIAL_CLEANUP_FUNC(char*, freecon);
DEFINE_TRIVIAL_CLEANUP_FUNC(context_t, context_free);
@@ -54,7 +54,7 @@ static struct selabel_handle *label_hnd = NULL;
#endif
bool mac_selinux_use(void) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
if (cached_use < 0)
cached_use = is_selinux_enabled() > 0;
@@ -65,7 +65,7 @@ bool mac_selinux_use(void) {
}
void mac_selinux_retest(void) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
cached_use = -1;
#endif
}
@@ -73,7 +73,7 @@ void mac_selinux_retest(void) {
int mac_selinux_init(void) {
int r = 0;
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
usec_t before_timestamp, after_timestamp;
struct mallinfo before_mallinfo, after_mallinfo;
@@ -110,7 +110,7 @@ int mac_selinux_init(void) {
void mac_selinux_finish(void) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
if (!label_hnd)
return;
@@ -121,7 +121,7 @@ void mac_selinux_finish(void) {
int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
struct stat st;
int r;
@@ -169,7 +169,7 @@ int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
int mac_selinux_apply(const char *path, const char *label) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
if (!mac_selinux_use())
return 0;
@@ -188,7 +188,7 @@ int mac_selinux_apply(const char *path, const char *label) {
int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
int r = -EOPNOTSUPP;
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
_cleanup_freecon_ char *mycon = NULL, *fcon = NULL;
security_class_t sclass;
@@ -220,7 +220,7 @@ int mac_selinux_get_our_label(char **label) {
assert(label);
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
if (!mac_selinux_use())
return -EOPNOTSUPP;
@@ -235,7 +235,7 @@ int mac_selinux_get_our_label(char **label) {
int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label) {
int r = -EOPNOTSUPP;
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
_cleanup_freecon_ char *mycon = NULL, *peercon = NULL, *fcon = NULL;
_cleanup_context_free_ context_t pcon = NULL, bcon = NULL;
security_class_t sclass;
@@ -296,7 +296,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
char* mac_selinux_free(char *label) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
if (!label)
return NULL;
@@ -312,7 +312,7 @@ char* mac_selinux_free(char *label) {
int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
_cleanup_freecon_ char *filecon = NULL;
int r;
@@ -355,7 +355,7 @@ int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
void mac_selinux_create_file_clear(void) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
PROTECT_ERRNO;
if (!mac_selinux_use())
@@ -367,7 +367,7 @@ void mac_selinux_create_file_clear(void) {
int mac_selinux_create_socket_prepare(const char *label) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
if (!mac_selinux_use())
return 0;
@@ -386,7 +386,7 @@ int mac_selinux_create_socket_prepare(const char *label) {
void mac_selinux_create_socket_clear(void) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
PROTECT_ERRNO;
if (!mac_selinux_use())
@@ -400,7 +400,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
/* Binds a socket and label its file system object according to the SELinux policy */
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
_cleanup_freecon_ char *fcon = NULL;
const struct sockaddr_un *un;
bool context_changed = false;
diff --git a/src/basic/set.c b/src/basic/set.c
new file mode 100644
index 0000000000..fd398b8212
--- /dev/null
+++ b/src/basic/set.c
@@ -0,0 +1,61 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2017 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "set.h"
+
+int set_make(Set **ret, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS, void *add, ...) {
+ _cleanup_set_free_ Set *s = NULL;
+ int r;
+
+ assert(ret);
+
+ s = set_new(hash_ops HASHMAP_DEBUG_PASS_ARGS);
+ if (!s)
+ return -ENOMEM;
+
+ if (add) {
+ va_list ap;
+
+ r = set_put(s, add);
+ if (r < 0)
+ return r;
+
+ va_start(ap, add);
+
+ for(;;) {
+ void *arg = va_arg(ap, void*);
+
+ if (!arg)
+ break;
+
+ r = set_put(s, arg);
+ if (r < 0) {
+ va_end(ap);
+ return r;
+ }
+ }
+
+ va_end(ap);
+ }
+
+ *ret = s;
+ s = NULL;
+
+ return 0;
+}
diff --git a/src/basic/set.h b/src/basic/set.h
index a5f8beb0c4..12d0fda1ca 100644
--- a/src/basic/set.h
+++ b/src/basic/set.h
@@ -136,3 +136,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free);
#define _cleanup_set_free_ _cleanup_(set_freep)
#define _cleanup_set_free_free_ _cleanup_(set_free_freep)
+
+int set_make(Set **ret, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS, void *add, ...);
diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c
index 280b5c3251..df6b742fde 100644
--- a/src/basic/signal-util.c
+++ b/src/basic/signal-util.c
@@ -38,7 +38,7 @@ int reset_all_signal_handlers(void) {
for (sig = 1; sig < _NSIG; sig++) {
/* These two cannot be caught... */
- if (sig == SIGKILL || sig == SIGSTOP)
+ if (IN_SET(sig, SIGKILL, SIGSTOP))
continue;
/* On Linux the first two RT signals are reserved by
diff --git a/src/basic/smack-util.c b/src/basic/smack-util.c
index 3a3df987df..3dcf150c59 100644
--- a/src/basic/smack-util.c
+++ b/src/basic/smack-util.c
@@ -35,7 +35,7 @@
#include "string-table.h"
#include "xattr-util.h"
-#ifdef HAVE_SMACK
+#if ENABLE_SMACK
bool mac_smack_use(void) {
static int cached_use = -1;
diff --git a/src/basic/socket-label.c b/src/basic/socket-label.c
index 6d1dc83874..6e7cdaac63 100644
--- a/src/basic/socket-label.c
+++ b/src/basic/socket-label.c
@@ -83,7 +83,7 @@ int socket_address_listen(
return -errno;
}
- if (socket_address_family(a) == AF_INET || socket_address_family(a) == AF_INET6) {
+ if (IN_SET(socket_address_family(a), AF_INET, AF_INET6)) {
if (bind_to_device)
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
return -errno;
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
index 016e64aa03..29c779552d 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -48,7 +48,7 @@
#include "utf8.h"
#include "util.h"
-#ifdef ENABLE_IDN
+#if ENABLE_IDN
# define IDN_FLAGS (NI_IDN|NI_IDN_USE_STD3_ASCII_RULES)
#else
# define IDN_FLAGS 0
@@ -268,7 +268,7 @@ int socket_address_verify(const SocketAddress *a) {
if (a->sockaddr.in.sin_port == 0)
return -EINVAL;
- if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
+ if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
return -EINVAL;
return 0;
@@ -280,7 +280,7 @@ int socket_address_verify(const SocketAddress *a) {
if (a->sockaddr.in6.sin6_port == 0)
return -EINVAL;
- if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
+ if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
return -EINVAL;
return 0;
@@ -304,7 +304,7 @@ int socket_address_verify(const SocketAddress *a) {
}
}
- if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
+ if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET))
return -EINVAL;
return 0;
@@ -314,7 +314,7 @@ int socket_address_verify(const SocketAddress *a) {
if (a->size != sizeof(struct sockaddr_nl))
return -EINVAL;
- if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
+ if (!IN_SET(a->type, SOCK_RAW, SOCK_DGRAM))
return -EINVAL;
return 0;
@@ -323,7 +323,7 @@ int socket_address_verify(const SocketAddress *a) {
if (a->size != sizeof(struct sockaddr_vm))
return -EINVAL;
- if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
+ if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
return -EINVAL;
return 0;
@@ -364,8 +364,7 @@ bool socket_address_can_accept(const SocketAddress *a) {
assert(a);
return
- a->type == SOCK_STREAM ||
- a->type == SOCK_SEQPACKET;
+ IN_SET(a->type, SOCK_STREAM, SOCK_SEQPACKET);
}
bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
@@ -793,7 +792,8 @@ static const char* const netlink_family_table[] = {
[NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
[NETLINK_GENERIC] = "generic",
[NETLINK_SCSITRANSPORT] = "scsitransport",
- [NETLINK_ECRYPTFS] = "ecryptfs"
+ [NETLINK_ECRYPTFS] = "ecryptfs",
+ [NETLINK_RDMA] = "rdma",
};
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
@@ -892,7 +892,7 @@ bool ifname_valid(const char *p) {
if ((unsigned char) *p <= 32U)
return false;
- if (*p == ':' || *p == '/')
+ if (IN_SET(*p, ':', '/'))
return false;
numeric = numeric && (*p >= '0' && *p <= '9');
@@ -1080,7 +1080,7 @@ ssize_t next_datagram_size_fd(int fd) {
l = recv(fd, NULL, 0, MSG_PEEK|MSG_TRUNC);
if (l < 0) {
- if (errno == EOPNOTSUPP || errno == EFAULT)
+ if (IN_SET(errno, EOPNOTSUPP, EFAULT))
goto fallback;
return -errno;
diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h
index 73c3a339fc..43edc05c63 100644
--- a/src/basic/socket-util.h
+++ b/src/basic/socket-util.h
@@ -27,6 +27,7 @@
#include <sys/types.h>
#include <sys/un.h>
#include <linux/netlink.h>
+#include <linux/if_infiniband.h>
#include <linux/if_packet.h>
#include "macro.h"
@@ -42,6 +43,8 @@ union sockaddr_union {
struct sockaddr_storage storage;
struct sockaddr_ll ll;
struct sockaddr_vm vm;
+ /* Ensure there is enough space to store Infiniband addresses */
+ uint8_t ll_buffer[offsetof(struct sockaddr_ll, sll_addr) + CONST_MAX(ETH_ALEN, INFINIBAND_ALEN)];
};
typedef struct SocketAddress {
@@ -147,6 +150,23 @@ int flush_accept(int fd);
struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length);
+/*
+ * Certain hardware address types (e.g Infiniband) do not fit into sll_addr
+ * (8 bytes) and run over the structure. This macro returns the correct size that
+ * must be passed to kernel.
+ */
+#define SOCKADDR_LL_LEN(sa) \
+ ({ \
+ const struct sockaddr_ll *_sa = &(sa); \
+ size_t _mac_len = sizeof(_sa->sll_addr); \
+ assert(_sa->sll_family == AF_PACKET); \
+ if (be16toh(_sa->sll_hatype) == ARPHRD_ETHER) \
+ _mac_len = MAX(_mac_len, (size_t) ETH_ALEN); \
+ if (be16toh(_sa->sll_hatype) == ARPHRD_INFINIBAND) \
+ _mac_len = MAX(_mac_len, (size_t) INFINIBAND_ALEN); \
+ offsetof(struct sockaddr_ll, sll_addr) + _mac_len; \
+ })
+
/* Covers only file system and abstract AF_UNIX socket addresses, but not unnamed socket addresses. */
#define SOCKADDR_UN_LEN(sa) \
({ \
diff --git a/src/basic/special.h b/src/basic/special.h
index feb8e5fe21..ddd4e84019 100644
--- a/src/basic/special.h
+++ b/src/basic/special.h
@@ -46,7 +46,6 @@
/* Early boot targets */
#define SPECIAL_SYSINIT_TARGET "sysinit.target"
#define SPECIAL_SOCKETS_TARGET "sockets.target"
-#define SPECIAL_BUSNAMES_TARGET "busnames.target"
#define SPECIAL_TIMERS_TARGET "timers.target"
#define SPECIAL_PATHS_TARGET "paths.target"
#define SPECIAL_LOCAL_FS_TARGET "local-fs.target"
diff --git a/src/basic/string-util.c b/src/basic/string-util.c
index 9d2f4bc8f9..3179fba3ba 100644
--- a/src/basic/string-util.c
+++ b/src/basic/string-util.c
@@ -215,7 +215,7 @@ char *strnappend(const char *s, const char *suffix, size_t b) {
}
char *strappend(const char *s, const char *suffix) {
- return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
+ return strnappend(s, suffix, strlen_ptr(suffix));
}
char *strjoin_real(const char *x, ...) {
@@ -542,7 +542,7 @@ char *ellipsize(const char *s, size_t length, unsigned percent) {
return ellipsize_mem(s, strlen(s), length, percent);
}
-bool nulstr_contains(const char*nulstr, const char *needle) {
+bool nulstr_contains(const char *nulstr, const char *needle) {
const char *i;
if (!nulstr)
@@ -558,7 +558,7 @@ bool nulstr_contains(const char*nulstr, const char *needle) {
char* strshorten(char *s, size_t l) {
assert(s);
- if (l < strlen(s))
+ if (strnlen(s, l+1) > l)
s[l] = 0;
return s;
@@ -635,6 +635,11 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
if (!f)
return NULL;
+ /* Note we use the _unlocked() stdio variants on f for performance
+ * reasons. It's safe to do so since we created f here and it
+ * doesn't leave our scope.
+ */
+
for (i = *ibuf; i < *ibuf + isz + 1; i++) {
switch (state) {
@@ -645,21 +650,21 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
else if (*i == '\x1B')
state = STATE_ESCAPE;
else if (*i == '\t')
- fputs(" ", f);
+ fputs_unlocked(" ", f);
else
- fputc(*i, f);
+ fputc_unlocked(*i, f);
break;
case STATE_ESCAPE:
if (i >= *ibuf + isz) { /* EOT */
- fputc('\x1B', f);
+ fputc_unlocked('\x1B', f);
break;
} else if (*i == '[') {
state = STATE_BRACKET;
begin = i + 1;
} else {
- fputc('\x1B', f);
- fputc(*i, f);
+ fputc_unlocked('\x1B', f);
+ fputc_unlocked(*i, f);
state = STATE_OTHER;
}
@@ -668,9 +673,9 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
case STATE_BRACKET:
if (i >= *ibuf + isz || /* EOT */
- (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) {
- fputc('\x1B', f);
- fputc('[', f);
+ (!(*i >= '0' && *i <= '9') && !IN_SET(*i, ';', 'm'))) {
+ fputc_unlocked('\x1B', f);
+ fputc_unlocked('[', f);
state = STATE_OTHER;
i = begin-1;
} else if (*i == 'm')
@@ -702,7 +707,7 @@ char *strextend(char **x, ...) {
assert(x);
- l = f = *x ? strlen(*x) : 0;
+ l = f = strlen_ptr(*x);
va_start(ap, x);
for (;;) {
@@ -821,7 +826,7 @@ int free_and_strdup(char **p, const char *s) {
return 1;
}
-#if !HAVE_DECL_EXPLICIT_BZERO
+#if !HAVE_EXPLICIT_BZERO
/*
* Pointer to memset is volatile so that compiler must de-reference
* the pointer and can't assume that it points to any function in
diff --git a/src/basic/string-util.h b/src/basic/string-util.h
index be44dedff4..4c94b182c1 100644
--- a/src/basic/string-util.h
+++ b/src/basic/string-util.h
@@ -120,7 +120,7 @@ char *strjoin_real(const char *x, ...) _sentinel_;
({ \
const char *_appendees_[] = { a, __VA_ARGS__ }; \
char *_d_, *_p_; \
- int _len_ = 0; \
+ size_t _len_ = 0; \
unsigned _i_; \
for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
_len_ += strlen(_appendees_[_i_]); \
@@ -158,7 +158,7 @@ bool string_has_cc(const char *p, const char *ok) _pure_;
char *ellipsize_mem(const char *s, size_t old_length_bytes, size_t new_length_columns, unsigned percent);
char *ellipsize(const char *s, size_t length, unsigned percent);
-bool nulstr_contains(const char*nulstr, const char *needle);
+bool nulstr_contains(const char *nulstr, const char *needle);
char* strshorten(char *s, size_t l);
@@ -189,7 +189,7 @@ static inline void *memmem_safe(const void *haystack, size_t haystacklen, const
return memmem(haystack, haystacklen, needle, needlelen);
}
-#if !HAVE_DECL_EXPLICIT_BZERO
+#if !HAVE_EXPLICIT_BZERO
void explicit_bzero(void *p, size_t l);
#endif
@@ -200,3 +200,10 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(char *, string_free_erase);
#define _cleanup_string_free_erase_ _cleanup_(string_free_erasep)
bool string_is_safe(const char *p) _pure_;
+
+static inline size_t strlen_ptr(const char *s) {
+ if (!s)
+ return 0;
+
+ return strlen(s);
+}
diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c
index 9a8ef825c5..28c8c35fe0 100644
--- a/src/basic/terminal-util.c
+++ b/src/basic/terminal-util.c
@@ -55,6 +55,7 @@
#include "terminal-util.h"
#include "time-util.h"
#include "util.h"
+#include "path-util.h"
static volatile unsigned cached_columns = 0;
static volatile unsigned cached_lines = 0;
@@ -244,6 +245,7 @@ int ask_string(char **ret, const char *text, ...) {
int reset_terminal_fd(int fd, bool switch_to_text) {
struct termios termios;
+ _cleanup_free_ char *utf8 = NULL;
int r = 0;
/* Set terminal to some sane defaults */
@@ -261,8 +263,8 @@ int reset_terminal_fd(int fd, bool switch_to_text) {
if (switch_to_text)
(void) ioctl(fd, KDSETMODE, KD_TEXT);
- /* Enable console unicode mode */
- (void) ioctl(fd, KDSKBMODE, K_UNICODE);
+ /* Set default keyboard mode */
+ (void) vt_reset_keyboard(fd);
if (tcgetattr(fd, &termios) < 0) {
r = -errno;
@@ -474,7 +476,7 @@ int acquire_terminal(
l = read(notify, &buffer, sizeof(buffer));
if (l < 0) {
- if (errno == EINTR || errno == EAGAIN)
+ if (IN_SET(errno, EINTR, EAGAIN))
continue;
r = -errno;
@@ -556,6 +558,7 @@ int terminal_vhangup(const char *name) {
int vt_disallocate(const char *name) {
_cleanup_close_ int fd = -1;
+ const char *e, *n;
unsigned u;
int r;
@@ -563,7 +566,8 @@ int vt_disallocate(const char *name) {
* (i.e. because it is the active one), at least clear it
* entirely (including the scrollback buffer) */
- if (!startswith(name, "/dev/"))
+ e = path_startswith(name, "/dev/");
+ if (!e)
return -EINVAL;
if (!tty_is_vc(name)) {
@@ -582,10 +586,11 @@ int vt_disallocate(const char *name) {
return 0;
}
- if (!startswith(name, "/dev/tty"))
+ n = startswith(e, "tty");
+ if (!n)
return -EINVAL;
- r = safe_atou(name+8, &u);
+ r = safe_atou(n, &u);
if (r < 0)
return r;
@@ -649,10 +654,7 @@ bool tty_is_vc(const char *tty) {
bool tty_is_console(const char *tty) {
assert(tty);
- if (startswith(tty, "/dev/"))
- tty += 5;
-
- return streq(tty, "console");
+ return streq(skip_dev_prefix(tty), "console");
}
int vtnr_from_tty(const char *tty) {
@@ -660,8 +662,7 @@ int vtnr_from_tty(const char *tty) {
assert(tty);
- if (startswith(tty, "/dev/"))
- tty += 5;
+ tty = skip_dev_prefix(tty);
if (!startswith(tty, "tty") )
return -EINVAL;
@@ -775,8 +776,7 @@ bool tty_is_vc_resolve(const char *tty) {
assert(tty);
- if (startswith(tty, "/dev/"))
- tty += 5;
+ tty = skip_dev_prefix(tty);
if (streq(tty, "console")) {
tty = resolve_dev_console(&active);
@@ -918,11 +918,9 @@ int getttyname_malloc(int fd, char **ret) {
r = ttyname_r(fd, path, sizeof(path));
if (r == 0) {
- const char *p;
char *c;
- p = startswith(path, "/dev/");
- c = strdup(p ?: path);
+ c = strdup(skip_dev_prefix(path));
if (!c)
return -ENOMEM;
@@ -1220,7 +1218,7 @@ bool colors_enabled(void) {
val = getenv_bool("SYSTEMD_COLORS");
if (val >= 0)
enabled = val;
- else if (getpid() == 1)
+ else if (getpid_cached() == 1)
/* PID1 outputs to the console without holding it open all the time */
enabled = !getenv_terminal_is_dumb();
else
@@ -1229,3 +1227,44 @@ bool colors_enabled(void) {
return enabled;
}
+
+bool underline_enabled(void) {
+ static int enabled = -1;
+
+ if (enabled < 0) {
+
+ /* The Linux console doesn't support underlining, turn it off, but only there. */
+
+ if (!colors_enabled())
+ enabled = false;
+ else
+ enabled = !streq_ptr(getenv("TERM"), "linux");
+ }
+
+ return enabled;
+}
+
+int vt_default_utf8(void) {
+ _cleanup_free_ char *b = NULL;
+ int r;
+
+ /* Read the default VT UTF8 setting from the kernel */
+
+ r = read_one_line_file("/sys/module/vt/parameters/default_utf8", &b);
+ if (r < 0)
+ return r;
+
+ return parse_boolean(b);
+}
+
+int vt_reset_keyboard(int fd) {
+ int kb;
+
+ /* If we can't read the default, then default to unicode. It's 2017 after all. */
+ kb = vt_default_utf8() != 0 ? K_UNICODE : K_XLATE;
+
+ if (ioctl(fd, KDSKBMODE, kb) < 0)
+ return -errno;
+
+ return 0;
+}
diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h
index b862bfaf05..c3045eb09d 100644
--- a/src/basic/terminal-util.h
+++ b/src/basic/terminal-util.h
@@ -86,6 +86,7 @@ void columns_lines_cache_reset(int _unused_ signum);
bool on_tty(void);
bool terminal_is_dumb(void);
bool colors_enabled(void);
+bool underline_enabled(void);
#define DEFINE_ANSI_FUNC(name, NAME) \
static inline const char *ansi_##name(void) { \
@@ -93,19 +94,28 @@ bool colors_enabled(void);
} \
struct __useless_struct_to_allow_trailing_semicolon__
-DEFINE_ANSI_FUNC(underline, UNDERLINE);
+#define DEFINE_ANSI_FUNC_UNDERLINE(name, NAME, REPLACEMENT) \
+ static inline const char *ansi_##name(void) { \
+ return underline_enabled() ? ANSI_##NAME : \
+ colors_enabled() ? ANSI_##REPLACEMENT : ""; \
+ } \
+ struct __useless_struct_to_allow_trailing_semicolon__
+
+
DEFINE_ANSI_FUNC(highlight, HIGHLIGHT);
-DEFINE_ANSI_FUNC(highlight_underline, HIGHLIGHT_UNDERLINE);
DEFINE_ANSI_FUNC(highlight_red, HIGHLIGHT_RED);
DEFINE_ANSI_FUNC(highlight_green, HIGHLIGHT_GREEN);
DEFINE_ANSI_FUNC(highlight_yellow, HIGHLIGHT_YELLOW);
DEFINE_ANSI_FUNC(highlight_blue, HIGHLIGHT_BLUE);
-DEFINE_ANSI_FUNC(highlight_red_underline, HIGHLIGHT_RED_UNDERLINE);
-DEFINE_ANSI_FUNC(highlight_green_underline, HIGHLIGHT_GREEN_UNDERLINE);
-DEFINE_ANSI_FUNC(highlight_yellow_underline, HIGHLIGHT_YELLOW_UNDERLINE);
-DEFINE_ANSI_FUNC(highlight_blue_underline, HIGHLIGHT_BLUE_UNDERLINE);
DEFINE_ANSI_FUNC(normal, NORMAL);
+DEFINE_ANSI_FUNC_UNDERLINE(underline, UNDERLINE, NORMAL);
+DEFINE_ANSI_FUNC_UNDERLINE(highlight_underline, HIGHLIGHT_UNDERLINE, HIGHLIGHT);
+DEFINE_ANSI_FUNC_UNDERLINE(highlight_red_underline, HIGHLIGHT_RED_UNDERLINE, HIGHLIGHT_RED);
+DEFINE_ANSI_FUNC_UNDERLINE(highlight_green_underline, HIGHLIGHT_GREEN_UNDERLINE, HIGHLIGHT_GREEN);
+DEFINE_ANSI_FUNC_UNDERLINE(highlight_yellow_underline, HIGHLIGHT_YELLOW_UNDERLINE, HIGHLIGHT_YELLOW);
+DEFINE_ANSI_FUNC_UNDERLINE(highlight_blue_underline, HIGHLIGHT_BLUE_UNDERLINE, HIGHLIGHT_BLUE);
+
int get_ctty_devnr(pid_t pid, dev_t *d);
int get_ctty(pid_t, dev_t *_devnr, char **r);
@@ -117,3 +127,6 @@ int ptsname_namespace(int pty, char **ret);
int openpt_in_namespace(pid_t pid, int flags);
int open_terminal_in_namespace(pid_t pid, const char *name, int mode);
+
+int vt_default_utf8(void);
+int vt_reset_keyboard(int fd);
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index 68ba86f6a5..f7f5e614f2 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -21,6 +21,7 @@
#include <limits.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/timerfd.h>
@@ -596,7 +597,7 @@ int timestamp_deserialize(const char *value, usec_t *timestamp) {
return r;
}
-int parse_timestamp(const char *t, usec_t *usec) {
+static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
static const struct {
const char *name;
const int nr;
@@ -617,7 +618,7 @@ int parse_timestamp(const char *t, usec_t *usec) {
{ "Sat", 6 },
};
- const char *k, *utc, *tzn = NULL;
+ const char *k, *utc = NULL, *tzn = NULL;
struct tm tm, copy;
time_t x;
usec_t x_usec, plus = 0, minus = 0, ret;
@@ -645,84 +646,86 @@ int parse_timestamp(const char *t, usec_t *usec) {
assert(t);
assert(usec);
- if (t[0] == '@')
+ if (t[0] == '@' && !with_tz)
return parse_sec(t + 1, usec);
ret = now(CLOCK_REALTIME);
- if (streq(t, "now"))
- goto finish;
+ if (!with_tz) {
+ if (streq(t, "now"))
+ goto finish;
- else if (t[0] == '+') {
- r = parse_sec(t+1, &plus);
- if (r < 0)
- return r;
+ else if (t[0] == '+') {
+ r = parse_sec(t+1, &plus);
+ if (r < 0)
+ return r;
- goto finish;
+ goto finish;
- } else if (t[0] == '-') {
- r = parse_sec(t+1, &minus);
- if (r < 0)
- return r;
+ } else if (t[0] == '-') {
+ r = parse_sec(t+1, &minus);
+ if (r < 0)
+ return r;
- goto finish;
+ goto finish;
- } else if ((k = endswith(t, " ago"))) {
- t = strndupa(t, k - t);
+ } else if ((k = endswith(t, " ago"))) {
+ t = strndupa(t, k - t);
- r = parse_sec(t, &minus);
- if (r < 0)
- return r;
+ r = parse_sec(t, &minus);
+ if (r < 0)
+ return r;
- goto finish;
+ goto finish;
- } else if ((k = endswith(t, " left"))) {
- t = strndupa(t, k - t);
+ } else if ((k = endswith(t, " left"))) {
+ t = strndupa(t, k - t);
- r = parse_sec(t, &plus);
- if (r < 0)
- return r;
+ r = parse_sec(t, &plus);
+ if (r < 0)
+ return r;
- goto finish;
- }
+ goto finish;
+ }
- /* See if the timestamp is suffixed with UTC */
- utc = endswith_no_case(t, " UTC");
- if (utc)
- t = strndupa(t, utc - t);
- else {
- const char *e = NULL;
- int j;
+ /* See if the timestamp is suffixed with UTC */
+ utc = endswith_no_case(t, " UTC");
+ if (utc)
+ t = strndupa(t, utc - t);
+ else {
+ const char *e = NULL;
+ int j;
- tzset();
+ tzset();
- /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note that we only
- * support the local timezones here, nothing else. Not because we wouldn't want to, but simply because
- * there are no nice APIs available to cover this. By accepting the local time zone strings, we make
- * sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't
- * support arbitrary timezone specifications. */
+ /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note that we only
+ * support the local timezones here, nothing else. Not because we wouldn't want to, but simply because
+ * there are no nice APIs available to cover this. By accepting the local time zone strings, we make
+ * sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't
+ * support arbitrary timezone specifications. */
- for (j = 0; j <= 1; j++) {
+ for (j = 0; j <= 1; j++) {
- if (isempty(tzname[j]))
- continue;
+ if (isempty(tzname[j]))
+ continue;
- e = endswith_no_case(t, tzname[j]);
- if (!e)
- continue;
- if (e == t)
- continue;
- if (e[-1] != ' ')
- continue;
+ e = endswith_no_case(t, tzname[j]);
+ if (!e)
+ continue;
+ if (e == t)
+ continue;
+ if (e[-1] != ' ')
+ continue;
- break;
- }
+ break;
+ }
- if (IN_SET(j, 0, 1)) {
- /* Found one of the two timezones specified. */
- t = strndupa(t, e - t - 1);
- dst = j;
- tzn = tzname[j];
+ if (IN_SET(j, 0, 1)) {
+ /* Found one of the two timezones specified. */
+ t = strndupa(t, e - t - 1);
+ dst = j;
+ tzn = tzname[j];
+ }
}
}
@@ -733,7 +736,7 @@ int parse_timestamp(const char *t, usec_t *usec) {
return -EINVAL;
tm.tm_isdst = dst;
- if (tzn)
+ if (!with_tz && tzn)
tm.tm_zone = tzn;
if (streq(t, "today")) {
@@ -846,11 +849,11 @@ parse_usec:
}
from_tm:
- x = mktime_or_timegm(&tm, utc);
- if (x < 0)
+ if (weekday >= 0 && tm.tm_wday != weekday)
return -EINVAL;
- if (weekday >= 0 && tm.tm_wday != weekday)
+ x = mktime_or_timegm(&tm, utc);
+ if (x < 0)
return -EINVAL;
ret = (usec_t) x * USEC_PER_SEC + x_usec;
@@ -874,6 +877,75 @@ finish:
return 0;
}
+typedef struct ParseTimestampResult {
+ usec_t usec;
+ int return_value;
+} ParseTimestampResult;
+
+int parse_timestamp(const char *t, usec_t *usec) {
+ char *last_space, *tz = NULL;
+ ParseTimestampResult *shared, tmp;
+ int r;
+ pid_t pid;
+
+ last_space = strrchr(t, ' ');
+ if (last_space != NULL && timezone_is_valid(last_space + 1))
+ tz = last_space + 1;
+
+ if (tz == NULL || endswith_no_case(t, " UTC"))
+ return parse_timestamp_impl(t, usec, false);
+
+ shared = mmap(NULL, sizeof *shared, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
+ if (shared == MAP_FAILED)
+ return negative_errno();
+
+ pid = fork();
+
+ if (pid == -1) {
+ int fork_errno = errno;
+ (void) munmap(shared, sizeof *shared);
+ return -fork_errno;
+ }
+
+ if (pid == 0) {
+ bool with_tz = true;
+
+ if (setenv("TZ", tz, 1) != 0) {
+ shared->return_value = negative_errno();
+ _exit(EXIT_FAILURE);
+ }
+
+ tzset();
+
+ /* If there is a timezone that matches the tzname fields, leave the parsing to the implementation.
+ * Otherwise just cut it off */
+ with_tz = !STR_IN_SET(tz, tzname[0], tzname[1]);
+
+ /*cut off the timezone if we dont need it*/
+ if (with_tz)
+ t = strndupa(t, last_space - t);
+
+ shared->return_value = parse_timestamp_impl(t, &shared->usec, with_tz);
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ r = wait_for_terminate(pid, NULL);
+ if (r < 0) {
+ (void) munmap(shared, sizeof *shared);
+ return r;
+ }
+
+ tmp = *shared;
+ if (munmap(shared, sizeof *shared) != 0)
+ return negative_errno();
+
+ if (tmp.return_value == 0)
+ *usec = tmp.usec;
+
+ return tmp.return_value;
+}
+
static char* extract_multiplier(char *p, usec_t *multiplier) {
static const struct {
const char *suffix;
@@ -1010,7 +1082,11 @@ int parse_sec(const char *t, usec_t *usec) {
}
int parse_sec_fix_0(const char *t, usec_t *usec) {
+ assert(t);
+ assert(usec);
+
t += strspn(t, WHITESPACE);
+
if (streq(t, "0")) {
*usec = USEC_INFINITY;
return 0;
@@ -1236,7 +1312,7 @@ bool timezone_is_valid(const char *name) {
if (!(*p >= '0' && *p <= '9') &&
!(*p >= 'a' && *p <= 'z') &&
!(*p >= 'A' && *p <= 'Z') &&
- !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
+ !IN_SET(*p, '-', '_', '+', '/'))
return false;
if (*p == '/') {
diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c
index 920ca0d9f5..f9c034c94b 100644
--- a/src/basic/unit-name.c
+++ b/src/basic/unit-name.c
@@ -305,7 +305,7 @@ static char *do_escape(const char *f, char *t) {
for (; *f; f++) {
if (*f == '/')
*(t++) = '-';
- else if (*f == '-' || *f == '\\' || !strchr(VALID_CHARS, *f))
+ else if (IN_SET(*f, '-', '\\') || !strchr(VALID_CHARS, *f))
t = do_escape_char(*f, t);
else
*(t++) = *f;
@@ -608,7 +608,6 @@ const char* unit_dbus_interface_from_type(UnitType t) {
static const char *const table[_UNIT_TYPE_MAX] = {
[UNIT_SERVICE] = "org.freedesktop.systemd1.Service",
[UNIT_SOCKET] = "org.freedesktop.systemd1.Socket",
- [UNIT_BUSNAME] = "org.freedesktop.systemd1.BusName",
[UNIT_TARGET] = "org.freedesktop.systemd1.Target",
[UNIT_DEVICE] = "org.freedesktop.systemd1.Device",
[UNIT_MOUNT] = "org.freedesktop.systemd1.Mount",
@@ -839,7 +838,6 @@ bool slice_name_is_valid(const char *name) {
static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
[UNIT_SERVICE] = "service",
[UNIT_SOCKET] = "socket",
- [UNIT_BUSNAME] = "busname",
[UNIT_TARGET] = "target",
[UNIT_DEVICE] = "device",
[UNIT_MOUNT] = "mount",
@@ -884,19 +882,6 @@ static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState);
-static const char* const busname_state_table[_BUSNAME_STATE_MAX] = {
- [BUSNAME_DEAD] = "dead",
- [BUSNAME_MAKING] = "making",
- [BUSNAME_REGISTERED] = "registered",
- [BUSNAME_LISTENING] = "listening",
- [BUSNAME_RUNNING] = "running",
- [BUSNAME_SIGTERM] = "sigterm",
- [BUSNAME_SIGKILL] = "sigkill",
- [BUSNAME_FAILED] = "failed",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState);
-
static const char* const device_state_table[_DEVICE_STATE_MAX] = {
[DEVICE_DEAD] = "dead",
[DEVICE_TENTATIVE] = "tentative",
@@ -912,8 +897,6 @@ static const char* const mount_state_table[_MOUNT_STATE_MAX] = {
[MOUNT_MOUNTED] = "mounted",
[MOUNT_REMOUNTING] = "remounting",
[MOUNT_UNMOUNTING] = "unmounting",
- [MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm",
- [MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill",
[MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm",
[MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill",
[MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm",
@@ -995,8 +978,6 @@ static const char* const swap_state_table[_SWAP_STATE_MAX] = {
[SWAP_ACTIVATING_DONE] = "activating-done",
[SWAP_ACTIVE] = "active",
[SWAP_DEACTIVATING] = "deactivating",
- [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm",
- [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill",
[SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm",
[SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill",
[SWAP_FAILED] = "failed"
diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h
index 0f164a6aa9..15558b4fbd 100644
--- a/src/basic/unit-name.h
+++ b/src/basic/unit-name.h
@@ -28,7 +28,6 @@
typedef enum UnitType {
UNIT_SERVICE = 0,
UNIT_SOCKET,
- UNIT_BUSNAME,
UNIT_TARGET,
UNIT_DEVICE,
UNIT_MOUNT,
@@ -73,19 +72,6 @@ typedef enum AutomountState {
_AUTOMOUNT_STATE_INVALID = -1
} AutomountState;
-typedef enum BusNameState {
- BUSNAME_DEAD,
- BUSNAME_MAKING,
- BUSNAME_REGISTERED,
- BUSNAME_LISTENING,
- BUSNAME_RUNNING,
- BUSNAME_SIGTERM,
- BUSNAME_SIGKILL,
- BUSNAME_FAILED,
- _BUSNAME_STATE_MAX,
- _BUSNAME_STATE_INVALID = -1
-} BusNameState;
-
/* We simply watch devices, we cannot plug/unplug them. That
* simplifies the state engine greatly */
typedef enum DeviceState {
@@ -103,8 +89,6 @@ typedef enum MountState {
MOUNT_MOUNTED,
MOUNT_REMOUNTING,
MOUNT_UNMOUNTING,
- MOUNT_MOUNTING_SIGTERM,
- MOUNT_MOUNTING_SIGKILL,
MOUNT_REMOUNTING_SIGTERM,
MOUNT_REMOUNTING_SIGKILL,
MOUNT_UNMOUNTING_SIGTERM,
@@ -186,8 +170,6 @@ typedef enum SwapState {
SWAP_ACTIVATING_DONE, /* /sbin/swapon is running, and the swap is done. */
SWAP_ACTIVE,
SWAP_DEACTIVATING,
- SWAP_ACTIVATING_SIGTERM,
- SWAP_ACTIVATING_SIGKILL,
SWAP_DEACTIVATING_SIGTERM,
SWAP_DEACTIVATING_SIGKILL,
SWAP_FAILED,
@@ -339,9 +321,6 @@ UnitActiveState unit_active_state_from_string(const char *s) _pure_;
const char* automount_state_to_string(AutomountState i) _const_;
AutomountState automount_state_from_string(const char *s) _pure_;
-const char* busname_state_to_string(BusNameState i) _const_;
-BusNameState busname_state_from_string(const char *s) _pure_;
-
const char* device_state_to_string(DeviceState i) _const_;
DeviceState device_state_from_string(const char *s) _pure_;
diff --git a/src/basic/user-util.c b/src/basic/user-util.c
index c619dad527..a691a0d3fc 100644
--- a/src/basic/user-util.c
+++ b/src/basic/user-util.c
@@ -543,8 +543,7 @@ bool valid_user_group_name(const char *u) {
if (!(*i >= 'a' && *i <= 'z') &&
!(*i >= 'A' && *i <= 'Z') &&
!(*i >= '0' && *i <= '9') &&
- *i != '_' &&
- *i != '-')
+ !IN_SET(*i, '_', '-'))
return false;
}
diff --git a/src/basic/utf8.c b/src/basic/utf8.c
index 6eae2b983d..7a52fac621 100644
--- a/src/basic/utf8.c
+++ b/src/basic/utf8.c
@@ -73,7 +73,7 @@ static bool unichar_is_control(char32_t ch) {
'\t' is in C0 range, but more or less harmless and commonly used.
*/
- return (ch < ' ' && ch != '\t' && ch != '\n') ||
+ return (ch < ' ' && !IN_SET(ch, '\t', '\n')) ||
(0x7F <= ch && ch <= 0x9F);
}
diff --git a/src/basic/util.c b/src/basic/util.c
index b52a5db31b..687de40993 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -34,6 +34,7 @@
#include <unistd.h>
#include "alloc-util.h"
+#include "btrfs-util.h"
#include "build.h"
#include "cgroup-util.h"
#include "def.h"
@@ -219,7 +220,7 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa
/* Spawns a temporary TTY agent, making sure it goes away when
* we go away */
- parent_pid = getpid();
+ parent_pid = getpid_cached();
/* First we temporarily block all signals, so that the new
* child has them blocked initially. This way, we can be sure
@@ -377,7 +378,7 @@ int on_ac_power(void) {
device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (device < 0) {
- if (errno == ENOENT || errno == ENOTDIR)
+ if (IN_SET(errno, ENOENT, ENOTDIR))
continue;
return -errno;
@@ -719,3 +720,133 @@ int version(void) {
SYSTEMD_FEATURES);
return 0;
}
+
+int get_block_device(const char *path, dev_t *dev) {
+ struct stat st;
+ struct statfs sfs;
+
+ assert(path);
+ assert(dev);
+
+ /* Get's the block device directly backing a file system. If
+ * the block device is encrypted, returns the device mapper
+ * block device. */
+
+ if (lstat(path, &st))
+ return -errno;
+
+ if (major(st.st_dev) != 0) {
+ *dev = st.st_dev;
+ return 1;
+ }
+
+ if (statfs(path, &sfs) < 0)
+ return -errno;
+
+ if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
+ return btrfs_get_block_device(path, dev);
+
+ return 0;
+}
+
+int get_block_device_harder(const char *path, dev_t *dev) {
+ _cleanup_closedir_ DIR *d = NULL;
+ _cleanup_free_ char *p = NULL, *t = NULL;
+ struct dirent *de, *found = NULL;
+ const char *q;
+ unsigned maj, min;
+ dev_t dt;
+ int r;
+
+ assert(path);
+ assert(dev);
+
+ /* Gets the backing block device for a file system, and
+ * handles LUKS encrypted file systems, looking for its
+ * immediate parent, if there is one. */
+
+ r = get_block_device(path, &dt);
+ if (r <= 0)
+ return r;
+
+ if (asprintf(&p, "/sys/dev/block/%u:%u/slaves", major(dt), minor(dt)) < 0)
+ return -ENOMEM;
+
+ d = opendir(p);
+ if (!d) {
+ if (errno == ENOENT)
+ goto fallback;
+
+ return -errno;
+ }
+
+ FOREACH_DIRENT_ALL(de, d, return -errno) {
+
+ if (dot_or_dot_dot(de->d_name))
+ continue;
+
+ if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
+ continue;
+
+ if (found) {
+ _cleanup_free_ char *u = NULL, *v = NULL, *a = NULL, *b = NULL;
+
+ /* We found a device backed by multiple other devices. We don't really support automatic
+ * discovery on such setups, with the exception of dm-verity partitions. In this case there are
+ * two backing devices: the data partition and the hash partition. We are fine with such
+ * setups, however, only if both partitions are on the same physical device. Hence, let's
+ * verify this. */
+
+ u = strjoin(p, "/", de->d_name, "/../dev");
+ if (!u)
+ return -ENOMEM;
+
+ v = strjoin(p, "/", found->d_name, "/../dev");
+ if (!v)
+ return -ENOMEM;
+
+ r = read_one_line_file(u, &a);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to read %s: %m", u);
+ goto fallback;
+ }
+
+ r = read_one_line_file(v, &b);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to read %s: %m", v);
+ goto fallback;
+ }
+
+ /* Check if the parent device is the same. If not, then the two backing devices are on
+ * different physical devices, and we don't support that. */
+ if (!streq(a, b))
+ goto fallback;
+ }
+
+ found = de;
+ }
+
+ if (!found)
+ goto fallback;
+
+ q = strjoina(p, "/", found->d_name, "/dev");
+
+ r = read_one_line_file(q, &t);
+ if (r == -ENOENT)
+ goto fallback;
+ if (r < 0)
+ return r;
+
+ if (sscanf(t, "%u:%u", &maj, &min) != 2)
+ return -EINVAL;
+
+ if (maj == 0)
+ goto fallback;
+
+ *dev = makedev(maj, min);
+ return 1;
+
+fallback:
+ *dev = dt;
+ return 1;
+}
diff --git a/src/basic/util.h b/src/basic/util.h
index c7da6c39bf..b31dfd1c92 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -192,3 +192,6 @@ uint64_t system_tasks_max_scale(uint64_t v, uint64_t max);
int update_reboot_parameter_and_warn(const char *param);
int version(void);
+
+int get_block_device(const char *path, dev_t *dev);
+int get_block_device_harder(const char *path, dev_t *dev);
diff --git a/src/basic/virt.c b/src/basic/virt.c
index 6011744523..d8eeb54dbf 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -46,6 +46,7 @@ static int detect_vm_cpuid(void) {
} cpuid_vendor_table[] = {
{ "XenVMMXenVMM", VIRTUALIZATION_XEN },
{ "KVMKVMKVM", VIRTUALIZATION_KVM },
+ { "TCGTCGTCGTCG", VIRTUALIZATION_QEMU },
/* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
{ "VMwareVMware", VIRTUALIZATION_VMWARE },
/* https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs */
@@ -421,7 +422,7 @@ int detect_container(void) {
goto finish;
}
- if (getpid() == 1) {
+ if (getpid_cached() == 1) {
/* If we are PID 1 we can just check our own environment variable, and that's authoritative. */
e = getenv("container");
diff --git a/src/basic/xattr-util.c b/src/basic/xattr-util.c
index 8256899eda..e086376d7c 100644
--- a/src/basic/xattr-util.c
+++ b/src/basic/xattr-util.c
@@ -129,7 +129,7 @@ static int parse_crtime(le64_t le, usec_t *usec) {
assert(usec);
u = le64toh(le);
- if (u == 0 || u == (uint64_t) -1)
+ if (IN_SET(u, 0, (uint64_t) -1))
return -EIO;
*usec = (usec_t) u;
diff --git a/src/basic/xml.c b/src/basic/xml.c
index 1dbeac7324..a4337f4865 100644
--- a/src/basic/xml.c
+++ b/src/basic/xml.c
@@ -208,7 +208,7 @@ int xml_tokenize(const char **p, char **name, void **state, unsigned *line) {
if (*c == '=') {
c++;
- if (*c == '\'' || *c == '\"') {
+ if (IN_SET(*c, '\'', '\"')) {
/* Tag with a quoted value */
e = strchr(c+1, *c);