1
0
mirror of https://github.com/systemd/systemd synced 2025-09-30 09:14:46 +02:00

Compare commits

...

22 Commits

Author SHA1 Message Date
Luca Boccassi
0f15cb2243
Merge pull request #18470 from mrc0mmand/ci-clang-12
ci: run build test with clang-12 as well
2021-02-09 13:06:40 +00:00
Zbigniew Jędrzejewski-Szmek
5bbf331434
Merge pull request #18416 from yuwata/strverscmp
util: introduce strverscmp_improved()
2021-02-09 14:06:18 +01:00
Zbigniew Jędrzejewski-Szmek
4ef8478eb5 fuzz-journal-remote: do not assert on resource conditions
We have a number of issues where oss-fuzz reports input-independent crashes of
fuzz-journal-remote. Instead of asserting that stuff that allocated fds and
memory never fails, let's instead just return an error.

https://oss-fuzz.com/testcase-detail/4791099424112640
https://oss-fuzz.com/testcase-detail/4531912477638656

I don't see any docs as to whether LLVMFuzzerTestOneInput() is allowed to
return non-zero. Propagating the error code is easiest, so let's just do that.
If it turns out that this causes oss-fuzz to still report a failure, we can
suppress that later.
2021-02-09 13:59:01 +01:00
Yu Watanabe
7bc38f59dc log: do not use uninitialized value
Follow-up for 85cf96e3f567cd51f79d671bbf3559550fdd67b7.
2021-02-09 13:58:12 +01:00
Frantisek Sumsal
67c972c610 ci: temporarily pin Arch repositories to glibc 2.32-5
glibc 2.33-3 shipped on 2021-02-06 breaks running Arch containers on
systems with older kernels (like Ubuntu Focal). Until the issue is
resolved, let's pin the Arch repositories to glibc 2.32-5 to mitigate
the annoying CI fails.

See: https://bugs.archlinux.org/task/69563
2021-02-09 13:57:28 +01:00
Zbigniew Jędrzejewski-Szmek
f47df388a0
Merge pull request #18346 from yuwata/hostnamectl-try-to-set-transient-hostname
hostnamectl: try to set transient hostname even if setting static or pretty hostname failed
2021-02-09 12:42:25 +01:00
Yu Watanabe
beb75dd31d test-network: support protocol and linkdown flag for ff00::/8 route
Fixes #18507.
2021-02-09 12:25:27 +01:00
Kevin P. Fleming
12f7469bbe network: Delay addition of IPv6 Proxy NDP addresses
Setting of IPv6 Proxy NDP addresses must be done at the same
time as static addresses, static routes, and other link attributes
that must be configured when the link is up. Doing this ensures
that they are reconfigured on the link if the link goes down
and returns to service.
2021-02-09 19:56:56 +09:00
Yu Watanabe
8087644a13 tree-wide: replace strverscmp() and str_verscmp() with strverscmp_improved() 2021-02-09 14:25:03 +09:00
Yu Watanabe
87b7d9b6ff string-util: introduce strverscmp_improved()
Unfortunately, strverscmp() from libc or str_verscmp() do not correctly
handle pre-release version, e.g. 247 vs 247~rc1.

This implement a new comparison function, which is based on the RPM's
rpmvercmp().
2021-02-09 14:24:58 +09:00
Yu Watanabe
e5bc5f1f5a fundamental: move several macros and functions into src/fundamental/
sd-boot has a copy of a subset of codes from libbasic. This makes
sd-boot share the code with libbasic, and dedup the code.

Note, startswith_no_case() is dropped from sd-boot, as
- it is not used,
- the previous implementation is not correct,
- gnu-efi does not have StrniCmp() or so.
2021-02-09 14:22:54 +09:00
Yu Watanabe
822be62fb2 hostnamectl: use Table 2021-02-09 13:49:27 +09:00
Yu Watanabe
f2d3ec7abf hostnamectl: show hint when user try to set transient hostname but static hostname is already used 2021-02-09 13:49:27 +09:00
Yu Watanabe
e8acf09186 hostname: use free_and_strdup_and_warn() 2021-02-09 13:49:27 +09:00
Yu Watanabe
ba12e41d05 hostname: re-read file later when failed to update file
Previously, even when writing e.g. /etc/hostname fails, the static
hostname in Context is not restored. So, the subsequent call of the same
method succeeds:
```
$ sudo chattr +i /etc/hostname
$ sudo hostnamectl --static set-hostname aaa
Could not set static hostname: Access denied
$ echo $?
1
$ sudo hostnamectl --static set-hostname aaa
$ echo $?
0
```

This makes when updating file is failed, the saved stat is cleared. So,
the static hostname or machine information in the context are always
consistent to the corresponding files.
2021-02-09 13:49:27 +09:00
Yu Watanabe
c388618ec0 hostnamectl: unset pretty hostname only when no target is specified 2021-02-09 13:49:27 +09:00
Yu Watanabe
2d79e90a1f hostnamectl: try to set transient hostname even if updating static or pretty hostname failed
If no target (--pretty, --static, or --transient) is specified, then
let's try to set transient hostname even if setting static or pretty
hostname failed. This may be useful for read-only filesystem.
2021-02-09 13:49:15 +09:00
Yu Watanabe
957991b7ac hostname: introduce two bus errors for updating file 2021-02-09 13:37:27 +09:00
Yu Watanabe
0ce2a086da bus-error: align error definitions 2021-02-09 13:37:27 +09:00
Yu Watanabe
5c3d2e3f43 hostnamectl: improve log message on failure 2021-02-09 13:37:27 +09:00
Frantisek Sumsal
8762049792 tree-wide: fix the string concatenation warning with clang-12
e.g.:
./src/shared/dissect-image.c:2218:39: error: suspicious concatenation of string literals in an array initialization; did you mean to separate the elements with a comma? [-Werror,-Wstring-concatenation]
                                      "/usr/lib/os-release\0",
                                      ^
../src/shared/dissect-image.c:2217:39: note: place parentheses around the string literal to silence warning
                [META_OS_RELEASE]   = "/etc/os-release\0"
                                      ^
1 error generated.

See: https://reviews.llvm.org/D85545
2021-02-08 12:22:03 +01:00
Frantisek Sumsal
19db2f4258 ci: run build test with clang-12 as well
Ubuntu repositories for clang 12 are finally up, so let's use it
in our CI.
2021-02-04 15:54:14 +01:00
41 changed files with 1114 additions and 739 deletions

View File

@ -21,6 +21,7 @@ jobs:
- { COMPILER: "gcc", COMPILER_VERSION: "10" }
- { COMPILER: "clang", COMPILER_VERSION: "10" }
- { COMPILER: "clang", COMPILER_VERSION: "11" }
- { COMPILER: "clang", COMPILER_VERSION: "12" }
env: ${{ matrix.env }}
steps:
- name: Repository checkout

View File

@ -29,6 +29,15 @@ jobs:
- name: Install
run: sudo apt-get update && sudo apt-get install --no-install-recommends python3-pexpect
# glibc 2.33-3 shipped on 2021-02-06 breaks running Arch containers on
# systems with older kernels (like Ubuntu Focal). Until the issue is
# resolved, let's pin the Arch repositories to glibc 2.32-5 to mitigate
# the annoying CI fails.
#
# See: https://bugs.archlinux.org/task/69563
- name: Pin repositories to 2021-02-05
run: sed -i '/^\[Distribution\]/aMirror=https://archive.archlinux.org/repos/2021/02/05/' .mkosi/mkosi.arch
- name: Symlink
run: ln -s .mkosi/mkosi.${{ matrix.distro }} mkosi.default

View File

@ -1616,6 +1616,7 @@ fuzzers = []
basic_includes = include_directories(
'src/basic',
'src/fundamental',
'src/systemd',
'.')
@ -1634,6 +1635,7 @@ includes = [libsystemd_includes, include_directories('src/shared')]
subdir('po')
subdir('catalog')
subdir('src/fundamental')
subdir('src/basic')
subdir('src/libsystemd')
subdir('src/shared')
@ -1664,6 +1666,7 @@ install_libsystemd_static = static_library(
libsystemd_sources,
basic_sources,
basic_gcrypt_sources,
fundamental_sources,
disable_mempool_c,
include_directories : libsystemd_includes,
build_by_default : static_libsystemd != 'false',
@ -1699,6 +1702,7 @@ libudev = shared_library(
install_libudev_static = static_library(
'udev',
basic_sources,
fundamental_sources,
shared_sources,
libsystemd_sources,
libudev_sources,

View File

@ -158,15 +158,6 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
(void*)memset(_new_, 0, _xsize_); \
})
/* Takes inspiration from Rust's Option::take() method: reads and returns a pointer, but at the same time
* resets it to NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */
#define TAKE_PTR(ptr) \
({ \
typeof(ptr) _ptr_ = (ptr); \
(ptr) = NULL; \
_ptr_; \
})
#if HAS_FEATURE_MEMORY_SANITIZER
# define msan_unpoison(r, s) __msan_unpoison(r, s)
#else

View File

@ -2164,7 +2164,7 @@ CGroupMask get_cpu_accounting_mask(void) {
struct utsname u;
assert_se(uname(&u) >= 0);
if (str_verscmp(u.release, "4.15") < 0)
if (strverscmp_improved(u.release, "4.15") < 0)
needed_mask = CGROUP_MASK_CPU;
else
needed_mask = 0;

View File

@ -1175,9 +1175,11 @@ static bool should_parse_proc_cmdline(void) {
/* For testing. */
return true;
if (parse_pid(e, &p) < 0)
if (parse_pid(e, &p) < 0) {
/* We know that systemd sets the variable correctly. Something else must have set it. */
log_debug("Failed to parse \"$SYSTEMD_EXEC_PID=%s\". Ignoring.", e);
return false;
}
return getpid_cached() == p;
}

View File

@ -9,6 +9,8 @@
#include <sys/sysmacros.h>
#include <sys/types.h>
#include "macro-fundamental.h"
#define _printf_(a, b) __attribute__((__format__(printf, a, b)))
#ifdef __clang__
# define _alloc_(...)
@ -18,10 +20,7 @@
#define _sentinel_ __attribute__((__sentinel__))
#define _section_(x) __attribute__((__section__(x)))
#define _used_ __attribute__((__used__))
#define _unused_ __attribute__((__unused__))
#define _destructor_ __attribute__((__destructor__))
#define _pure_ __attribute__((__pure__))
#define _const_ __attribute__((__const__))
#define _deprecated_ __attribute__((__deprecated__))
#define _packed_ __attribute__((__packed__))
#define _malloc_ __attribute__((__malloc__))
@ -34,7 +33,6 @@
#define _align_(x) __attribute__((__aligned__(x)))
#define _alignas_(x) __attribute__((__aligned__(__alignof(x))))
#define _alignptr_ __attribute__((__aligned__(sizeof(void*))))
#define _cleanup_(x) __attribute__((__cleanup__(x)))
#if __GNUC__ >= 7
#define _fallthrough_ __attribute__((__fallthrough__))
#else
@ -143,12 +141,6 @@
#define XSTRINGIFY(x) #x
#define STRINGIFY(x) XSTRINGIFY(x)
#define XCONCATENATE(x, y) x ## y
#define CONCATENATE(x, y) XCONCATENATE(x, y)
#define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq))
#define UNIQ __COUNTER__
/* builtins */
#if __SIZEOF_INT__ == 4
#define BUILTIN_FFS_U32(x) __builtin_ffs(x);
@ -222,18 +214,6 @@ static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) {
return m;
}
#ifndef __COVERITY__
# define VOID_0 ((void)0)
#else
# define VOID_0 ((void*)0)
#endif
#define ELEMENTSOF(x) \
(__builtin_choose_expr( \
!__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \
sizeof(x)/sizeof((x)[0]), \
VOID_0))
/*
* STRLEN - return the length of a string literal, minus the trailing NUL byte.
* Contrary to strlen(), this is a constant expression.
@ -254,106 +234,6 @@ static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) {
(type*)( (char *)UNIQ_T(A, uniq) - offsetof(type, member) ); \
})
#undef MAX
#define MAX(a, b) __MAX(UNIQ, (a), UNIQ, (b))
#define __MAX(aq, a, bq, b) \
({ \
const typeof(a) UNIQ_T(A, aq) = (a); \
const typeof(b) UNIQ_T(B, bq) = (b); \
UNIQ_T(A, aq) > UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \
})
/* evaluates to (void) if _A or _B are not constant or of different types */
#define CONST_MAX(_A, _B) \
(__builtin_choose_expr( \
__builtin_constant_p(_A) && \
__builtin_constant_p(_B) && \
__builtin_types_compatible_p(typeof(_A), typeof(_B)), \
((_A) > (_B)) ? (_A) : (_B), \
VOID_0))
/* takes two types and returns the size of the larger one */
#define MAXSIZE(A, B) (sizeof(union _packed_ { typeof(A) a; typeof(B) b; }))
#define MAX3(x, y, z) \
({ \
const typeof(x) _c = MAX(x, y); \
MAX(_c, z); \
})
#define MAX4(x, y, z, a) \
({ \
const typeof(x) _d = MAX3(x, y, z); \
MAX(_d, a); \
})
#undef MIN
#define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b))
#define __MIN(aq, a, bq, b) \
({ \
const typeof(a) UNIQ_T(A, aq) = (a); \
const typeof(b) UNIQ_T(B, bq) = (b); \
UNIQ_T(A, aq) < UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \
})
/* evaluates to (void) if _A or _B are not constant or of different types */
#define CONST_MIN(_A, _B) \
(__builtin_choose_expr( \
__builtin_constant_p(_A) && \
__builtin_constant_p(_B) && \
__builtin_types_compatible_p(typeof(_A), typeof(_B)), \
((_A) < (_B)) ? (_A) : (_B), \
VOID_0))
#define MIN3(x, y, z) \
({ \
const typeof(x) _c = MIN(x, y); \
MIN(_c, z); \
})
#define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b))
#define __LESS_BY(aq, a, bq, b) \
({ \
const typeof(a) UNIQ_T(A, aq) = (a); \
const typeof(b) UNIQ_T(B, bq) = (b); \
UNIQ_T(A, aq) > UNIQ_T(B, bq) ? UNIQ_T(A, aq) - UNIQ_T(B, bq) : 0; \
})
#define CMP(a, b) __CMP(UNIQ, (a), UNIQ, (b))
#define __CMP(aq, a, bq, b) \
({ \
const typeof(a) UNIQ_T(A, aq) = (a); \
const typeof(b) UNIQ_T(B, bq) = (b); \
UNIQ_T(A, aq) < UNIQ_T(B, bq) ? -1 : \
UNIQ_T(A, aq) > UNIQ_T(B, bq) ? 1 : 0; \
})
#undef CLAMP
#define CLAMP(x, low, high) __CLAMP(UNIQ, (x), UNIQ, (low), UNIQ, (high))
#define __CLAMP(xq, x, lowq, low, highq, high) \
({ \
const typeof(x) UNIQ_T(X, xq) = (x); \
const typeof(low) UNIQ_T(LOW, lowq) = (low); \
const typeof(high) UNIQ_T(HIGH, highq) = (high); \
UNIQ_T(X, xq) > UNIQ_T(HIGH, highq) ? \
UNIQ_T(HIGH, highq) : \
UNIQ_T(X, xq) < UNIQ_T(LOW, lowq) ? \
UNIQ_T(LOW, lowq) : \
UNIQ_T(X, xq); \
})
/* [(x + y - 1) / y] suffers from an integer overflow, even though the
* computation should be possible in the given type. Therefore, we use
* [x / y + !!(x % y)]. Note that on "Real CPUs" a division returns both the
* quotient and the remainder, so both should be equally fast. */
#define DIV_ROUND_UP(x, y) __DIV_ROUND_UP(UNIQ, (x), UNIQ, (y))
#define __DIV_ROUND_UP(xq, x, yq, y) \
({ \
const typeof(x) UNIQ_T(X, xq) = (x); \
const typeof(y) UNIQ_T(Y, yq) = (y); \
(UNIQ_T(X, xq) / UNIQ_T(Y, yq) + !!(UNIQ_T(X, xq) % UNIQ_T(Y, yq))); \
})
#ifdef __COVERITY__
/* Use special definitions of assertion macros in order to prevent
@ -410,16 +290,6 @@ static inline int __coverity_check_and_return__(int condition) {
#define assert_not_reached(t) \
log_assert_failed_unreachable(t, PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__)
#if defined(static_assert)
#define assert_cc(expr) \
static_assert(expr, #expr)
#else
#define assert_cc(expr) \
struct CONCATENATE(_assert_struct_, __COUNTER__) { \
char x[(expr) ? 0 : -1]; \
}
#endif
#define assert_return(expr, r) \
do { \
if (!assert_log(expr, #expr)) \
@ -498,53 +368,6 @@ static inline int __coverity_check_and_return__(int condition) {
#define FLAGS_SET(v, flags) \
((~(v) & (flags)) == 0)
#define CASE_F(X) case X:
#define CASE_F_1(CASE, X) CASE_F(X)
#define CASE_F_2(CASE, X, ...) CASE(X) CASE_F_1(CASE, __VA_ARGS__)
#define CASE_F_3(CASE, X, ...) CASE(X) CASE_F_2(CASE, __VA_ARGS__)
#define CASE_F_4(CASE, X, ...) CASE(X) CASE_F_3(CASE, __VA_ARGS__)
#define CASE_F_5(CASE, X, ...) CASE(X) CASE_F_4(CASE, __VA_ARGS__)
#define CASE_F_6(CASE, X, ...) CASE(X) CASE_F_5(CASE, __VA_ARGS__)
#define CASE_F_7(CASE, X, ...) CASE(X) CASE_F_6(CASE, __VA_ARGS__)
#define CASE_F_8(CASE, X, ...) CASE(X) CASE_F_7(CASE, __VA_ARGS__)
#define CASE_F_9(CASE, X, ...) CASE(X) CASE_F_8(CASE, __VA_ARGS__)
#define CASE_F_10(CASE, X, ...) CASE(X) CASE_F_9(CASE, __VA_ARGS__)
#define CASE_F_11(CASE, X, ...) CASE(X) CASE_F_10(CASE, __VA_ARGS__)
#define CASE_F_12(CASE, X, ...) CASE(X) CASE_F_11(CASE, __VA_ARGS__)
#define CASE_F_13(CASE, X, ...) CASE(X) CASE_F_12(CASE, __VA_ARGS__)
#define CASE_F_14(CASE, X, ...) CASE(X) CASE_F_13(CASE, __VA_ARGS__)
#define CASE_F_15(CASE, X, ...) CASE(X) CASE_F_14(CASE, __VA_ARGS__)
#define CASE_F_16(CASE, X, ...) CASE(X) CASE_F_15(CASE, __VA_ARGS__)
#define CASE_F_17(CASE, X, ...) CASE(X) CASE_F_16(CASE, __VA_ARGS__)
#define CASE_F_18(CASE, X, ...) CASE(X) CASE_F_17(CASE, __VA_ARGS__)
#define CASE_F_19(CASE, X, ...) CASE(X) CASE_F_18(CASE, __VA_ARGS__)
#define CASE_F_20(CASE, X, ...) CASE(X) CASE_F_19(CASE, __VA_ARGS__)
#define GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME
#define FOR_EACH_MAKE_CASE(...) \
GET_CASE_F(__VA_ARGS__,CASE_F_20,CASE_F_19,CASE_F_18,CASE_F_17,CASE_F_16,CASE_F_15,CASE_F_14,CASE_F_13,CASE_F_12,CASE_F_11, \
CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \
(CASE_F,__VA_ARGS__)
#define IN_SET(x, ...) \
({ \
bool _found = false; \
/* If the build breaks in the line below, you need to extend the case macros. (We use "long double" as \
* type for the array, in the hope that checkers such as ubsan don't complain that the initializers for \
* the array are not representable by the base type. Ideally we'd use typeof(x) as base type, but that \
* doesn't work, as we want to use this on bitfields and gcc refuses typeof() on bitfields.) */ \
static const long double __assert_in_set[] _unused_ = { __VA_ARGS__ }; \
assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \
switch(x) { \
FOR_EACH_MAKE_CASE(__VA_ARGS__) \
_found = true; \
break; \
default: \
break; \
} \
_found; \
})
#define SWAP_TWO(x, y) do { \
typeof(x) _t = (x); \
(x) = (y); \

View File

@ -381,6 +381,7 @@ run_target(
libbasic = static_library(
'basic',
basic_sources,
fundamental_sources,
include_directories : basic_includes,
dependencies : [versiondep,
threads,

View File

@ -20,64 +20,6 @@
#include "utf8.h"
#include "util.h"
int strcmp_ptr(const char *a, const char *b) {
/* Like strcmp(), but tries to make sense of NULL pointers */
if (a && b)
return strcmp(a, b);
return CMP(a, b); /* Direct comparison of pointers, one of which is NULL */
}
int strcasecmp_ptr(const char *a, const char *b) {
/* Like strcasecmp(), but tries to make sense of NULL pointers */
if (a && b)
return strcasecmp(a, b);
return CMP(a, b); /* Direct comparison of pointers, one of which is NULL */
}
char* endswith(const char *s, const char *postfix) {
size_t sl, pl;
assert(s);
assert(postfix);
sl = strlen(s);
pl = strlen(postfix);
if (pl == 0)
return (char*) s + sl;
if (sl < pl)
return NULL;
if (memcmp(s + sl - pl, postfix, pl) != 0)
return NULL;
return (char*) s + sl - pl;
}
char* endswith_no_case(const char *s, const char *postfix) {
size_t sl, pl;
assert(s);
assert(postfix);
sl = strlen(s);
pl = strlen(postfix);
if (pl == 0)
return (char*) s + sl;
if (sl < pl)
return NULL;
if (strcasecmp(s + sl - pl, postfix) != 0)
return NULL;
return (char*) s + sl - pl;
}
char* first_word(const char *s, const char *word) {
size_t sl, wl;
const char *p;

View File

@ -7,6 +7,7 @@
#include "alloc-util.h"
#include "macro.h"
#include "string-util-fundamental.h"
/* What is interpreted as whitespace? */
#define WHITESPACE " \t\n\r"
@ -21,22 +22,6 @@
#define ALPHANUMERICAL LETTERS DIGITS
#define HEXDIGITS DIGITS "abcdefABCDEF"
#define streq(a,b) (strcmp((a),(b)) == 0)
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0)
#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0)
int strcmp_ptr(const char *a, const char *b) _pure_;
int strcasecmp_ptr(const char *a, const char *b) _pure_;
static inline bool streq_ptr(const char *a, const char *b) {
return strcmp_ptr(a, b) == 0;
}
static inline bool strcaseeq_ptr(const char *a, const char *b) {
return strcasecmp_ptr(a, b) == 0;
}
static inline char* strstr_ptr(const char *haystack, const char *needle) {
if (!haystack || !needle)
return NULL;
@ -55,10 +40,6 @@ static inline const char *strna(const char *s) {
return s ?: "n/a";
}
static inline const char* yes_no(bool b) {
return b ? "yes" : "no";
}
static inline const char* true_false(bool b) {
return b ? "true" : "false";
}
@ -75,10 +56,6 @@ static inline const char* enable_disable(bool b) {
return b ? "enable" : "disable";
}
static inline bool isempty(const char *p) {
return !p || !p[0];
}
static inline const char *empty_to_null(const char *p) {
return isempty(p) ? NULL : p;
}
@ -97,29 +74,6 @@ static inline const char *empty_or_dash_to_null(const char *p) {
return empty_or_dash(p) ? NULL : p;
}
static inline char *startswith(const char *s, const char *prefix) {
size_t l;
l = strlen(prefix);
if (strncmp(s, prefix, l) == 0)
return (char*) s + l;
return NULL;
}
static inline char *startswith_no_case(const char *s, const char *prefix) {
size_t l;
l = strlen(prefix);
if (strncasecmp(s, prefix, l) == 0)
return (char*) s + l;
return NULL;
}
char *endswith(const char *s, const char *postfix) _pure_;
char *endswith_no_case(const char *s, const char *postfix) _pure_;
char *first_word(const char *s, const char *word) _pure_;
char *strnappend(const char *s, const char *suffix, size_t length);

View File

@ -227,68 +227,6 @@ int version(void) {
return 0;
}
/* This is a direct translation of str_verscmp from boot.c */
static bool is_digit(int c) {
return c >= '0' && c <= '9';
}
static int c_order(int c) {
if (c == 0 || is_digit(c))
return 0;
if ((c >= 'a') && (c <= 'z'))
return c;
return c + 0x10000;
}
int str_verscmp(const char *s1, const char *s2) {
const char *os1, *os2;
assert(s1);
assert(s2);
os1 = s1;
os2 = s2;
while (*s1 || *s2) {
int first;
while ((*s1 && !is_digit(*s1)) || (*s2 && !is_digit(*s2))) {
int order;
order = c_order(*s1) - c_order(*s2);
if (order != 0)
return order;
s1++;
s2++;
}
while (*s1 == '0')
s1++;
while (*s2 == '0')
s2++;
first = 0;
while (is_digit(*s1) && is_digit(*s2)) {
if (first == 0)
first = *s1 - *s2;
s1++;
s2++;
}
if (is_digit(*s1))
return 1;
if (is_digit(*s2))
return -1;
if (first != 0)
return first;
}
return strcmp(os1, os2);
}
/* Turn off core dumps but only if we're running outside of a container. */
void disable_coredumps(void) {
int r;

View File

@ -63,6 +63,4 @@ int container_get_leader(const char *machine, pid_t *pid);
int version(void);
int str_verscmp(const char *s1, const char *s2);
void disable_coredumps(void);

View File

@ -471,7 +471,7 @@ static int compare_version(const char *a, const char *b) {
b += strcspn(b, " ");
b += strspn(b, " ");
return strverscmp(a, b);
return strverscmp_improved(a, b);
}
static int version_check(int fd_from, const char *from, int fd_to, const char *to) {

View File

@ -7,9 +7,9 @@
#include "console.h"
#include "crc32.h"
#include "disk.h"
#include "efi-loader-features.h"
#include "graphics.h"
#include "linux.h"
#include "loader-features.h"
#include "measure.h"
#include "pe.h"
#include "random-seed.h"
@ -914,63 +914,6 @@ static VOID config_entry_free(ConfigEntry *entry) {
FreePool(entry);
}
static BOOLEAN is_digit(CHAR16 c) {
return (c >= '0') && (c <= '9');
}
static UINTN c_order(CHAR16 c) {
if (c == '\0')
return 0;
if (is_digit(c))
return 0;
else if ((c >= 'a') && (c <= 'z'))
return c;
else
return c + 0x10000;
}
static INTN str_verscmp(CHAR16 *s1, CHAR16 *s2) {
CHAR16 *os1 = s1;
CHAR16 *os2 = s2;
while (*s1 || *s2) {
INTN first;
while ((*s1 && !is_digit(*s1)) || (*s2 && !is_digit(*s2))) {
INTN order;
order = c_order(*s1) - c_order(*s2);
if (order != 0)
return order;
s1++;
s2++;
}
while (*s1 == '0')
s1++;
while (*s2 == '0')
s2++;
first = 0;
while (is_digit(*s1) && is_digit(*s2)) {
if (first == 0)
first = *s1 - *s2;
s1++;
s2++;
}
if (is_digit(*s1))
return 1;
if (is_digit(*s2))
return -1;
if (first != 0)
return first;
}
return StrCmp(os1, os2);
}
static CHAR8 *line_get_key_value(
CHAR8 *content,
CHAR8 *sep,
@ -1535,7 +1478,7 @@ static INTN config_entry_compare(ConfigEntry *a, ConfigEntry *b) {
if (a->tries_left == 0 && b->tries_left != 0)
return -1;
r = str_verscmp(a->id, b->id);
r = strverscmp_improved(a->id, b->id);
if (r != 0)
return r;

View File

@ -145,6 +145,8 @@ if have_gnu_efi
'-Wno-missing-field-initializers',
'-isystem', efi_incdir,
'-isystem', join_paths(efi_incdir, gnu_efi_path_arch),
'-I', fundamental_path,
'-DSD_BOOT',
'-include', efi_config_h,
'-include', version_h]
if efi_arch == 'x86_64'
@ -194,17 +196,17 @@ if have_gnu_efi
systemd_boot_objects = []
stub_objects = []
foreach file : common_sources + systemd_boot_sources + stub_sources
o_file = custom_target(file + '.o',
foreach file : fundamental_source_paths + common_sources + systemd_boot_sources + stub_sources
o_file = custom_target(file.split('/')[-1] + '.o',
input : file,
output : file + '.o',
output : file.split('/')[-1] + '.o',
command : efi_cc + ['-c', '@INPUT@', '-o', '@OUTPUT@']
+ compile_args,
depend_files : efi_headers)
if (common_sources + systemd_boot_sources).contains(file)
depend_files : efi_headers + fundamental_headers)
if (fundamental_source_paths + common_sources + systemd_boot_sources).contains(file)
systemd_boot_objects += o_file
endif
if (common_sources + stub_sources).contains(file)
if (fundamental_source_paths + common_sources + stub_sources).contains(file)
stub_objects += o_file
endif
endforeach

View File

@ -369,62 +369,6 @@ CHAR8 *strchra(CHAR8 *s, CHAR8 c) {
return NULL;
}
const CHAR16 *startswith(const CHAR16 *s, const CHAR16 *prefix) {
UINTN l;
l = StrLen(prefix);
if (StrnCmp(s, prefix, l) == 0)
return s + l;
return NULL;
}
const CHAR16 *endswith(const CHAR16 *s, const CHAR16 *postfix) {
UINTN sl, pl;
sl = StrLen(s);
pl = StrLen(postfix);
if (pl == 0)
return s + sl;
if (sl < pl)
return NULL;
if (StrnCmp(s + sl - pl, postfix, pl) != 0)
return NULL;
return s + sl - pl;
}
const CHAR16 *startswith_no_case(const CHAR16 *s, const CHAR16 *prefix) {
UINTN l;
l = StrLen(prefix);
if (StriCmp(s, prefix) == 0)
return s + l;
return NULL;
}
const CHAR16 *endswith_no_case(const CHAR16 *s, const CHAR16 *postfix) {
UINTN sl, pl;
sl = StrLen(s);
pl = StrLen(postfix);
if (pl == 0)
return s + sl;
if (sl < pl)
return NULL;
if (StriCmp(s + sl - pl, postfix) != 0)
return NULL;
return s + sl - pl;
}
EFI_STATUS file_read(EFI_FILE_HANDLE dir, const CHAR16 *name, UINTN off, UINTN size, CHAR8 **ret, UINTN *ret_size) {
_cleanup_(FileHandleClosep) EFI_FILE_HANDLE handle = NULL;
_cleanup_freepool_ CHAR8 *buf = NULL;

View File

@ -4,17 +4,14 @@
#include <efi.h>
#include <efilib.h>
#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
#include "string-util-fundamental.h"
#define OFFSETOF(x,y) __builtin_offsetof(x,y)
static inline UINTN ALIGN_TO(UINTN l, UINTN ali) {
return ((l + ali - 1) & ~(ali - 1));
}
static inline const CHAR16 *yes_no(BOOLEAN b) {
return b ? L"yes" : L"no";
}
EFI_STATUS parse_boolean(const CHAR8 *v, BOOLEAN *b);
UINT64 ticks_read(void);
@ -39,12 +36,6 @@ CHAR8 *strchra(CHAR8 *s, CHAR8 c);
CHAR16 *stra_to_path(CHAR8 *stra);
CHAR16 *stra_to_str(CHAR8 *stra);
const CHAR16 *startswith(const CHAR16 *s, const CHAR16 *prefix);
const CHAR16 *endswith(const CHAR16 *s, const CHAR16 *postfix);
const CHAR16 *startswith_no_case(const CHAR16 *s, const CHAR16 *prefix);
const CHAR16 *endswith_no_case(const CHAR16 *s, const CHAR16 *postfix);
EFI_STATUS file_read(EFI_FILE_HANDLE dir, const CHAR16 *name, UINTN off, UINTN size, CHAR8 **content, UINTN *content_size);
static inline void FreePoolp(void *p) {
@ -56,7 +47,6 @@ static inline void FreePoolp(void *p) {
FreePool(q);
}
#define _cleanup_(x) __attribute__((__cleanup__(x)))
#define _cleanup_freepool_ _cleanup_(FreePoolp)
static inline void FileHandleClosep(EFI_FILE_HANDLE *handle) {
@ -78,11 +68,4 @@ static inline void FileHandleClosep(EFI_FILE_HANDLE *handle) {
#define UINTN_MAX (~(UINTN)0)
#define INTN_MAX ((INTN)(UINTN_MAX>>1))
#define TAKE_PTR(ptr) \
({ \
typeof(ptr) _ptr_ = (ptr); \
(ptr) = NULL; \
_ptr_; \
})
EFI_STATUS log_oom(void);

View File

@ -0,0 +1,201 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#ifndef SD_BOOT
#include <assert.h>
#endif
#include "type.h"
#define _const_ __attribute__((__const__))
#define _pure_ __attribute__((__pure__))
#define _unused_ __attribute__((__unused__))
#define _cleanup_(x) __attribute__((__cleanup__(x)))
#ifndef __COVERITY__
# define VOID_0 ((void)0)
#else
# define VOID_0 ((void*)0)
#endif
#define ELEMENTSOF(x) \
(__builtin_choose_expr( \
!__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \
sizeof(x)/sizeof((x)[0]), \
VOID_0))
#define XCONCATENATE(x, y) x ## y
#define CONCATENATE(x, y) XCONCATENATE(x, y)
#ifdef SD_BOOT
#define assert(expr) do {} while (false)
#endif
#if defined(static_assert)
#define assert_cc(expr) \
static_assert(expr, #expr)
#else
#define assert_cc(expr) \
struct CONCATENATE(_assert_struct_, __COUNTER__) { \
char x[(expr) ? 0 : -1]; \
}
#endif
#define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq))
#define UNIQ __COUNTER__
#undef MAX
#define MAX(a, b) __MAX(UNIQ, (a), UNIQ, (b))
#define __MAX(aq, a, bq, b) \
({ \
const typeof(a) UNIQ_T(A, aq) = (a); \
const typeof(b) UNIQ_T(B, bq) = (b); \
UNIQ_T(A, aq) > UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \
})
/* evaluates to (void) if _A or _B are not constant or of different types */
#define CONST_MAX(_A, _B) \
(__builtin_choose_expr( \
__builtin_constant_p(_A) && \
__builtin_constant_p(_B) && \
__builtin_types_compatible_p(typeof(_A), typeof(_B)), \
((_A) > (_B)) ? (_A) : (_B), \
VOID_0))
/* takes two types and returns the size of the larger one */
#define MAXSIZE(A, B) (sizeof(union _packed_ { typeof(A) a; typeof(B) b; }))
#define MAX3(x, y, z) \
({ \
const typeof(x) _c = MAX(x, y); \
MAX(_c, z); \
})
#define MAX4(x, y, z, a) \
({ \
const typeof(x) _d = MAX3(x, y, z); \
MAX(_d, a); \
})
#undef MIN
#define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b))
#define __MIN(aq, a, bq, b) \
({ \
const typeof(a) UNIQ_T(A, aq) = (a); \
const typeof(b) UNIQ_T(B, bq) = (b); \
UNIQ_T(A, aq) < UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \
})
/* evaluates to (void) if _A or _B are not constant or of different types */
#define CONST_MIN(_A, _B) \
(__builtin_choose_expr( \
__builtin_constant_p(_A) && \
__builtin_constant_p(_B) && \
__builtin_types_compatible_p(typeof(_A), typeof(_B)), \
((_A) < (_B)) ? (_A) : (_B), \
VOID_0))
#define MIN3(x, y, z) \
({ \
const typeof(x) _c = MIN(x, y); \
MIN(_c, z); \
})
#define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b))
#define __LESS_BY(aq, a, bq, b) \
({ \
const typeof(a) UNIQ_T(A, aq) = (a); \
const typeof(b) UNIQ_T(B, bq) = (b); \
UNIQ_T(A, aq) > UNIQ_T(B, bq) ? UNIQ_T(A, aq) - UNIQ_T(B, bq) : 0; \
})
#define CMP(a, b) __CMP(UNIQ, (a), UNIQ, (b))
#define __CMP(aq, a, bq, b) \
({ \
const typeof(a) UNIQ_T(A, aq) = (a); \
const typeof(b) UNIQ_T(B, bq) = (b); \
UNIQ_T(A, aq) < UNIQ_T(B, bq) ? -1 : \
UNIQ_T(A, aq) > UNIQ_T(B, bq) ? 1 : 0; \
})
#undef CLAMP
#define CLAMP(x, low, high) __CLAMP(UNIQ, (x), UNIQ, (low), UNIQ, (high))
#define __CLAMP(xq, x, lowq, low, highq, high) \
({ \
const typeof(x) UNIQ_T(X, xq) = (x); \
const typeof(low) UNIQ_T(LOW, lowq) = (low); \
const typeof(high) UNIQ_T(HIGH, highq) = (high); \
UNIQ_T(X, xq) > UNIQ_T(HIGH, highq) ? \
UNIQ_T(HIGH, highq) : \
UNIQ_T(X, xq) < UNIQ_T(LOW, lowq) ? \
UNIQ_T(LOW, lowq) : \
UNIQ_T(X, xq); \
})
/* [(x + y - 1) / y] suffers from an integer overflow, even though the
* computation should be possible in the given type. Therefore, we use
* [x / y + !!(x % y)]. Note that on "Real CPUs" a division returns both the
* quotient and the remainder, so both should be equally fast. */
#define DIV_ROUND_UP(x, y) __DIV_ROUND_UP(UNIQ, (x), UNIQ, (y))
#define __DIV_ROUND_UP(xq, x, yq, y) \
({ \
const typeof(x) UNIQ_T(X, xq) = (x); \
const typeof(y) UNIQ_T(Y, yq) = (y); \
(UNIQ_T(X, xq) / UNIQ_T(Y, yq) + !!(UNIQ_T(X, xq) % UNIQ_T(Y, yq))); \
})
#define CASE_F(X) case X:
#define CASE_F_1(CASE, X) CASE_F(X)
#define CASE_F_2(CASE, X, ...) CASE(X) CASE_F_1(CASE, __VA_ARGS__)
#define CASE_F_3(CASE, X, ...) CASE(X) CASE_F_2(CASE, __VA_ARGS__)
#define CASE_F_4(CASE, X, ...) CASE(X) CASE_F_3(CASE, __VA_ARGS__)
#define CASE_F_5(CASE, X, ...) CASE(X) CASE_F_4(CASE, __VA_ARGS__)
#define CASE_F_6(CASE, X, ...) CASE(X) CASE_F_5(CASE, __VA_ARGS__)
#define CASE_F_7(CASE, X, ...) CASE(X) CASE_F_6(CASE, __VA_ARGS__)
#define CASE_F_8(CASE, X, ...) CASE(X) CASE_F_7(CASE, __VA_ARGS__)
#define CASE_F_9(CASE, X, ...) CASE(X) CASE_F_8(CASE, __VA_ARGS__)
#define CASE_F_10(CASE, X, ...) CASE(X) CASE_F_9(CASE, __VA_ARGS__)
#define CASE_F_11(CASE, X, ...) CASE(X) CASE_F_10(CASE, __VA_ARGS__)
#define CASE_F_12(CASE, X, ...) CASE(X) CASE_F_11(CASE, __VA_ARGS__)
#define CASE_F_13(CASE, X, ...) CASE(X) CASE_F_12(CASE, __VA_ARGS__)
#define CASE_F_14(CASE, X, ...) CASE(X) CASE_F_13(CASE, __VA_ARGS__)
#define CASE_F_15(CASE, X, ...) CASE(X) CASE_F_14(CASE, __VA_ARGS__)
#define CASE_F_16(CASE, X, ...) CASE(X) CASE_F_15(CASE, __VA_ARGS__)
#define CASE_F_17(CASE, X, ...) CASE(X) CASE_F_16(CASE, __VA_ARGS__)
#define CASE_F_18(CASE, X, ...) CASE(X) CASE_F_17(CASE, __VA_ARGS__)
#define CASE_F_19(CASE, X, ...) CASE(X) CASE_F_18(CASE, __VA_ARGS__)
#define CASE_F_20(CASE, X, ...) CASE(X) CASE_F_19(CASE, __VA_ARGS__)
#define GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME
#define FOR_EACH_MAKE_CASE(...) \
GET_CASE_F(__VA_ARGS__,CASE_F_20,CASE_F_19,CASE_F_18,CASE_F_17,CASE_F_16,CASE_F_15,CASE_F_14,CASE_F_13,CASE_F_12,CASE_F_11, \
CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \
(CASE_F,__VA_ARGS__)
#define IN_SET(x, ...) \
({ \
sd_bool _found = false; \
/* If the build breaks in the line below, you need to extend the case macros. (We use "long double" as \
* type for the array, in the hope that checkers such as ubsan don't complain that the initializers for \
* the array are not representable by the base type. Ideally we'd use typeof(x) as base type, but that \
* doesn't work, as we want to use this on bitfields and gcc refuses typeof() on bitfields.) */ \
static const long double __assert_in_set[] _unused_ = { __VA_ARGS__ }; \
assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \
switch(x) { \
FOR_EACH_MAKE_CASE(__VA_ARGS__) \
_found = true; \
break; \
default: \
break; \
} \
_found; \
})
/* Takes inspiration from Rust's Option::take() method: reads and returns a pointer, but at the same time
* resets it to NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */
#define TAKE_PTR(ptr) \
({ \
typeof(ptr) _ptr_ = (ptr); \
(ptr) = NULL; \
_ptr_; \
})

View File

@ -0,0 +1,22 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
fundamental_path = meson.current_source_dir()
fundamental_headers = files(
'efi-loader-features.h',
'macro-fundamental.h',
'string-util-fundamental.h',
'type.h')
sources = '''
string-util-fundamental.c
'''.split()
# for sd-boot
fundamental_source_paths = []
foreach s : sources
fundamental_source_paths += join_paths(meson.current_source_dir(), s)
endforeach
# for libbasic
fundamental_sources = files(sources) + fundamental_headers

View File

@ -0,0 +1,234 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#ifndef SD_BOOT
#include <ctype.h>
#include "macro.h"
#endif
#include "string-util-fundamental.h"
sd_char *startswith(const sd_char *s, const sd_char *prefix) {
sd_size_t l;
assert(s);
assert(prefix);
l = strlen(prefix);
if (!strneq(s, prefix, l))
return NULL;
return (sd_char*) s + l;
}
#ifndef SD_BOOT
sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) {
sd_size_t l;
assert(s);
assert(prefix);
l = strlen(prefix);
if (!strncaseeq(s, prefix, l))
return NULL;
return (sd_char*) s + l;
}
#endif
sd_char* endswith(const sd_char *s, const sd_char *postfix) {
sd_size_t sl, pl;
assert(s);
assert(postfix);
sl = strlen(s);
pl = strlen(postfix);
if (pl == 0)
return (sd_char*) s + sl;
if (sl < pl)
return NULL;
if (strcmp(s + sl - pl, postfix) != 0)
return NULL;
return (sd_char*) s + sl - pl;
}
sd_char* endswith_no_case(const sd_char *s, const sd_char *postfix) {
sd_size_t sl, pl;
assert(s);
assert(postfix);
sl = strlen(s);
pl = strlen(postfix);
if (pl == 0)
return (sd_char*) s + sl;
if (sl < pl)
return NULL;
if (strcasecmp(s + sl - pl, postfix) != 0)
return NULL;
return (sd_char*) s + sl - pl;
}
#ifdef SD_BOOT
static sd_bool isdigit(sd_char a) {
return a >= '0' && a <= '9';
}
#endif
static sd_bool is_alpha(sd_char a) {
/* Locale independent version of isalpha(). */
return (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
}
static sd_bool is_valid_version_char(sd_char a) {
return isdigit(a) || is_alpha(a) || IN_SET(a, '~', '-', '^', '.');
}
sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
/* This is based on RPM's rpmvercmp(). But this explicitly handles '-' and '.', as we usually
* want to directly compare strings which contain both version and release; e.g.
* '247.2-3.1.fc33.x86_64' or '5.11.0-0.rc5.20210128git76c057c84d28.137.fc34'.
* Unlike rpmvercmp(), this distiguishes e.g. 123a and 123.a, and 123a is newer.
*
* This splits the input strings into segments. Each segment is numeric or alpha, and may be
* prefixed with the following:
* '~' : used for pre-releases, a segment prefixed with this is the oldest,
* '-' : used for the separator between version and release,
* '^' : used for patched releases, a segment with this is newer than one with '-'.
* '.' : used for point releases.
* Note, no prefix segment is the newest. All non-supported characters are dropped, and
* handled as a separator of segments, e.g., 123_a is equivalent to 123a.
*
* By using this, version strings can be sorted like following:
* (older) 122.1
* ^ 123~rc1-1
* | 123
* | 123-a
* | 123-a.1
* | 123-1
* | 123-1.1
* | 123^post1
* | 123.a-1
* | 123.1-1
* v 123a-1
* (newer) 124-1
*/
if (isempty(a) || isempty(b))
return strcmp_ptr(a, b);
for (;;) {
const sd_char *aa, *bb;
sd_int r;
/* Drop leading invalid characters. */
while (*a != '\0' && !is_valid_version_char(*a))
a++;
while (*b != '\0' && !is_valid_version_char(*b))
b++;
/* Handle '~'. Used for pre-releases, e.g. 123~rc1, or 4.5~alpha1 */
if (*a == '~' || *b == '~') {
/* The string prefixed with '~' is older. */
r = CMP(*a != '~', *b != '~');
if (r != 0)
return r;
/* Now both strings are prefixed with '~'. Compare remaining strings. */
a++;
b++;
}
/* If at least one string reaches the end, then longer is newer.
* Note that except for '~' prefixed segments, a string has more segments is newer.
* So, this check must be after the '~' check. */
if (*a == '\0' || *b == '\0')
return strcmp(a, b);
/* Handle '-', which separates version and release, e.g 123.4-3.1.fc33.x86_64 */
if (*a == '-' || *b == '-') {
/* The string prefixed with '-' is older (e.g., 123-9 vs 123.1-1) */
r = CMP(*a != '-', *b != '-');
if (r != 0)
return r;
a++;
b++;
}
/* Handle '^'. Used for patched release. */
if (*a == '^' || *b == '^') {
r = CMP(*a != '^', *b != '^');
if (r != 0)
return r;
a++;
b++;
}
/* Handle '.'. Used for point releases. */
if (*a == '.' || *b == '.') {
r = CMP(*a != '.', *b != '.');
if (r != 0)
return r;
a++;
b++;
}
if (isdigit(*a) || isdigit(*b)) {
/* Skip leading '0', to make 00123 equivalent to 123. */
while (*a == '0')
a++;
while (*b == '0')
b++;
/* Find the leading numeric segments. One may be an empty string. So,
* numeric segments are always newer than alpha segments. */
for (aa = a; *aa != '\0' && isdigit(*aa); aa++)
;
for (bb = b; *bb != '\0' && isdigit(*bb); bb++)
;
/* To compare numeric segments without parsing their values, first compare the
* lengths of the segments. Eg. 12345 vs 123, longer is newer. */
r = CMP(aa - a, bb - b);
if (r != 0)
return r;
/* Then, compare them as strings. */
r = strncmp(a, b, aa - a);
if (r != 0)
return r;
} else {
/* Find the leading non-numeric segments. */
for (aa = a; *aa != '\0' && is_alpha(*aa); aa++)
;
for (bb = b; *bb != '\0' && is_alpha(*bb); bb++)
;
/* Note that the segments are usually not NUL-terminated. */
r = strncmp(a, b, MIN(aa - a, bb - b));
if (r != 0)
return r;
/* Longer is newer, e.g. abc vs abcde. */
r = CMP(aa - a, bb - b);
if (r != 0)
return r;
}
/* The current segments are equivalent. Let's compare the next one. */
a = aa;
b = bb;
}
}

View File

@ -0,0 +1,67 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#ifdef SD_BOOT
#include <efi.h>
#include <efilib.h>
#else
#include <string.h>
#endif
#include "macro-fundamental.h"
#ifdef SD_BOOT
#define strlen(a) StrLen((a))
#define strcmp(a, b) StrCmp((a), (b))
#define strncmp(a, b, n) StrnCmp((a), (b), (n))
#define strcasecmp(a, b) StriCmp((a), (b))
#define STR_C(str) (L ## str)
#else
#define STR_C(str) (str)
#endif
#define streq(a,b) (strcmp((a),(b)) == 0)
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0)
#ifndef SD_BOOT
#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0)
#endif
static inline sd_int strcmp_ptr(const sd_char *a, const sd_char *b) {
if (a && b)
return strcmp(a, b);
return CMP(a, b);
}
static inline sd_int strcasecmp_ptr(const sd_char *a, const sd_char *b) {
if (a && b)
return strcasecmp(a, b);
return CMP(a, b);
}
static inline sd_bool streq_ptr(const sd_char *a, const sd_char *b) {
return strcmp_ptr(a, b) == 0;
}
static inline sd_bool strcaseeq_ptr(const sd_char *a, const sd_char *b) {
return strcasecmp_ptr(a, b) == 0;
}
sd_char *startswith(const sd_char *s, const sd_char *prefix) _pure_;
#ifndef SD_BOOT
sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) _pure_;
#endif
sd_char *endswith(const sd_char *s, const sd_char *postfix) _pure_;
sd_char *endswith_no_case(const sd_char *s, const sd_char *postfix) _pure_;
static inline sd_bool isempty(const sd_char *a) {
return !a || a[0] == '\0';
}
static inline const sd_char *yes_no(sd_bool b) {
return b ? STR_C("yes") : STR_C("no");
}
sd_int strverscmp_improved(const sd_char *a, const sd_char *b);

22
src/fundamental/type.h Normal file
View File

@ -0,0 +1,22 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#ifdef SD_BOOT
#include <efi.h>
typedef BOOLEAN sd_bool;
typedef CHAR16 sd_char;
typedef INTN sd_int;
typedef UINTN sd_size_t;
#define true TRUE
#define false FALSE
#else
#include <stdbool.h>
#include <stdint.h>
typedef bool sd_bool;
typedef char sd_char;
typedef int sd_int;
typedef size_t sd_size_t;
#endif

View File

@ -11,8 +11,11 @@
#include "alloc-util.h"
#include "architecture.h"
#include "bus-common-errors.h"
#include "bus-error.h"
#include "bus-map-properties.h"
#include "format-table.h"
#include "hostname-setup.h"
#include "hostname-util.h"
#include "main-func.h"
#include "pretty-print.h"
@ -47,46 +50,109 @@ typedef struct StatusInfo {
const char *hardware_model;
} StatusInfo;
static void print_status_info(StatusInfo *i) {
static int print_status_info(StatusInfo *i) {
_cleanup_(table_unrefp) Table *table = NULL;
sd_id128_t mid = {}, bid = {};
TableCell *cell;
int r;
assert(i);
printf(" Static hostname: %s\n", strna(i->static_hostname));
table = table_new("key", "value");
if (!table)
return log_oom();
assert_se(cell = table_get_cell(table, 0, 0));
(void) table_set_ellipsize_percent(table, cell, 100);
(void) table_set_align_percent(table, cell, 100);
table_set_header(table, false);
r = table_set_empty_string(table, "n/a");
if (r < 0)
return log_oom();
r = table_add_many(table,
TABLE_STRING, "Static hostname:",
TABLE_STRING, i->static_hostname);
if (r < 0)
return table_log_add_error(r);
if (!isempty(i->pretty_hostname) &&
!streq_ptr(i->pretty_hostname, i->static_hostname))
printf(" Pretty hostname: %s\n", i->pretty_hostname);
!streq_ptr(i->pretty_hostname, i->static_hostname)) {
r = table_add_many(table,
TABLE_STRING, "Pretty hostname:",
TABLE_STRING, i->pretty_hostname);
if (r < 0)
return table_log_add_error(r);
}
if (!isempty(i->hostname) &&
!streq_ptr(i->hostname, i->static_hostname))
printf("Transient hostname: %s\n", i->hostname);
!streq_ptr(i->hostname, i->static_hostname)) {
r = table_add_many(table,
TABLE_STRING, "Transient hostname:",
TABLE_STRING, i->hostname);
if (r < 0)
return table_log_add_error(r);
}
if (!isempty(i->icon_name))
printf(" Icon name: %s\n",
strna(i->icon_name));
if (!isempty(i->icon_name)) {
r = table_add_many(table,
TABLE_STRING, "Icon name:",
TABLE_STRING, i->icon_name);
if (r < 0)
return table_log_add_error(r);
}
if (!isempty(i->chassis))
printf(" Chassis: %s\n",
strna(i->chassis));
if (!isempty(i->chassis)) {
r = table_add_many(table,
TABLE_STRING, "Chassis:",
TABLE_STRING, i->chassis);
if (r < 0)
return table_log_add_error(r);
}
if (!isempty(i->deployment))
printf(" Deployment: %s\n", i->deployment);
if (!isempty(i->deployment)) {
r = table_add_many(table,
TABLE_STRING, "Deployment:",
TABLE_STRING, i->deployment);
if (r < 0)
return table_log_add_error(r);
}
if (!isempty(i->location))
printf(" Location: %s\n", i->location);
if (!isempty(i->location)) {
r = table_add_many(table,
TABLE_STRING, "Location:",
TABLE_STRING, i->location);
if (r < 0)
return table_log_add_error(r);
}
r = sd_id128_get_machine(&mid);
if (r >= 0)
printf(" Machine ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(mid));
if (r >= 0) {
r = table_add_many(table,
TABLE_STRING, "Machine ID:",
TABLE_ID128, mid);
if (r < 0)
return table_log_add_error(r);
}
r = sd_id128_get_boot(&bid);
if (r >= 0)
printf(" Boot ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(bid));
if (r >= 0) {
r = table_add_many(table,
TABLE_STRING, "Boot ID:",
TABLE_ID128, bid);
if (r < 0)
return table_log_add_error(r);
}
if (!isempty(i->virtualization))
printf(" Virtualization: %s\n", i->virtualization);
if (!isempty(i->virtualization)) {
r = table_add_many(table,
TABLE_STRING, "Virtualization:",
TABLE_STRING, i->virtualization);
if (r < 0)
return table_log_add_error(r);
}
if (!isempty(i->os_pretty_name)) {
_cleanup_free_ char *formatted = NULL;
@ -97,31 +163,74 @@ static void print_status_info(StatusInfo *i) {
t = formatted;
}
printf(" Operating System: %s\n", t);
r = table_add_many(table,
TABLE_STRING, "Operating System:",
TABLE_STRING, t);
if (r < 0)
return table_log_add_error(r);
}
if (!isempty(i->os_cpe_name))
printf(" CPE OS Name: %s\n", i->os_cpe_name);
if (!isempty(i->os_cpe_name)) {
r = table_add_many(table,
TABLE_STRING, "CPE OS Name:",
TABLE_STRING, i->os_cpe_name);
if (r < 0)
return table_log_add_error(r);
}
if (!isempty(i->kernel_name) && !isempty(i->kernel_release))
printf(" Kernel: %s %s\n", i->kernel_name, i->kernel_release);
if (!isempty(i->kernel_name) && !isempty(i->kernel_release)) {
const char *v;
if (!isempty(i->architecture))
printf(" Architecture: %s\n", i->architecture);
v = strjoina(i->kernel_name, " ", i->kernel_release);
r = table_add_many(table,
TABLE_STRING, "Kernel:",
TABLE_STRING, v);
if (r < 0)
return table_log_add_error(r);
}
if (!isempty(i->hardware_vendor))
printf(" Hardware Vendor: %s\n", i->hardware_vendor);
if (!isempty(i->architecture)) {
r = table_add_many(table,
TABLE_STRING, "Architecture:",
TABLE_STRING, i->architecture);
if (r < 0)
return table_log_add_error(r);
}
if (!isempty(i->hardware_model))
printf(" Hardware Model: %s\n", i->hardware_model);
if (!isempty(i->hardware_vendor)) {
r = table_add_many(table,
TABLE_STRING, "Hardware Vendor:",
TABLE_STRING, i->hardware_vendor);
if (r < 0)
return table_log_add_error(r);
}
if (!isempty(i->hardware_model)) {
r = table_add_many(table,
TABLE_STRING, "Hardware Model:",
TABLE_STRING, i->hardware_model);
if (r < 0)
return table_log_add_error(r);
}
r = table_print(table, NULL);
if (r < 0)
return table_log_print_error(r);
return 0;
}
static int show_one_name(sd_bus *bus, const char* attr) {
static int get_one_name(sd_bus *bus, const char* attr, char **ret) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
const char *s;
int r;
assert(bus);
assert(attr);
/* This obtains one string property, and copy it if 'ret' is set, or print it otherwise. */
r = sd_bus_get_property(
bus,
"org.freedesktop.hostname1",
@ -136,12 +245,21 @@ static int show_one_name(sd_bus *bus, const char* attr) {
if (r < 0)
return bus_log_parse_error(r);
if (ret) {
char *str;
str = strdup(s);
if (!str)
return log_oom();
*ret = str;
} else
printf("%s\n", s);
return 0;
}
static int show_all_names(sd_bus *bus, sd_bus_error *error) {
static int show_all_names(sd_bus *bus) {
StatusInfo info = {};
static const struct bus_properties_map hostname_map[] = {
@ -169,6 +287,7 @@ static int show_all_names(sd_bus *bus, sd_bus_error *error) {
};
_cleanup_(sd_bus_message_unrefp) sd_bus_message *host_message = NULL, *manager_message = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
r = bus_map_all_properties(bus,
@ -176,29 +295,28 @@ static int show_all_names(sd_bus *bus, sd_bus_error *error) {
"/org/freedesktop/hostname1",
hostname_map,
0,
error,
&error,
&host_message,
&info);
if (r < 0)
return r;
return log_error_errno(r, "Failed to query system properties: %s", bus_error_message(&error, r));
r = bus_map_all_properties(bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
manager_map,
0,
error,
&error,
&manager_message,
&info);
if (r < 0)
return log_error_errno(r, "Failed to query system properties: %s", bus_error_message(&error, r));
print_status_info(&info);
return r;
return print_status_info(&info);
}
static int show_status(int argc, char **argv, void *userdata) {
sd_bus *bus = userdata;
int r;
if (arg_pretty || arg_static || arg_transient) {
const char *attr;
@ -210,61 +328,83 @@ static int show_status(int argc, char **argv, void *userdata) {
attr = arg_pretty ? "PrettyHostname" :
arg_static ? "StaticHostname" : "Hostname";
return show_one_name(bus, attr);
} else {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
r = show_all_names(bus, &error);
if (r < 0)
return log_error_errno(r, "Failed to query system properties: %s", bus_error_message(&error, r));
return 0;
return get_one_name(bus, attr, NULL);
}
return show_all_names(bus);
}
static int set_simple_string(sd_bus *bus, const char *method, const char *value) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r = 0;
static int set_simple_string_internal(sd_bus *bus, sd_bus_error *error, const char *target, const char *method, const char *value) {
_cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL;
int r;
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
if (!error)
error = &e;
r = sd_bus_call_method(
bus,
"org.freedesktop.hostname1",
"/org/freedesktop/hostname1",
"org.freedesktop.hostname1",
method,
&error, NULL,
error, NULL,
"sb", value, arg_ask_password);
if (r < 0)
return log_error_errno(r, "Could not set property: %s", bus_error_message(&error, r));
return log_error_errno(r, "Could not set %s: %s", target, bus_error_message(error, r));
return 0;
}
static int set_simple_string(sd_bus *bus, const char *target, const char *method, const char *value) {
return set_simple_string_internal(bus, NULL, target, method, value);
}
static int set_hostname(int argc, char **argv, void *userdata) {
_cleanup_free_ char *h = NULL;
const char *hostname = argv[1];
sd_bus *bus = userdata;
int r;
bool implicit = false, show_hint = false;
int r, ret = 0;
if (!arg_pretty && !arg_static && !arg_transient)
arg_pretty = arg_static = arg_transient = true;
arg_pretty = arg_static = arg_transient = implicit = true;
if (!implicit && !arg_static && arg_transient) {
_cleanup_free_ char *source = NULL;
r = get_one_name(bus, "HostnameSource", &source);
if (r < 0)
return r;
if (hostname_source_from_string(source) == HOSTNAME_STATIC)
log_info("Hint: static hostname is already set, so the specified transient hostname will not be used.");
}
if (arg_pretty) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
const char *p;
/* If the passed hostname is already valid, then assume the user doesn't know anything about pretty
* hostnames, so let's unset the pretty hostname, and just set the passed hostname as static/dynamic
* hostname. */
if (arg_static && hostname_is_valid(hostname, VALID_HOSTNAME_TRAILING_DOT))
if (implicit && hostname_is_valid(hostname, VALID_HOSTNAME_TRAILING_DOT))
p = ""; /* No pretty hostname (as it is redundant), just a static one */
else
p = hostname; /* Use the passed name as pretty hostname */
r = set_simple_string(bus, "SetPrettyHostname", p);
if (r < 0)
r = set_simple_string_internal(bus, &error, "pretty hostname", "SetPrettyHostname", p);
if (r < 0) {
if (implicit &&
sd_bus_error_has_names(&error,
BUS_ERROR_FILE_IS_PROTECTED,
BUS_ERROR_READ_ONLY_FILESYSTEM)) {
show_hint = true;
ret = r;
} else
return r;
}
/* Now that we set the pretty hostname, let's clean up the parameter and use that as static
* hostname. If the hostname was already valid as static hostname, this will only chop off the trailing
@ -280,34 +420,47 @@ static int set_hostname(int argc, char **argv, void *userdata) {
}
if (arg_static) {
r = set_simple_string(bus, "SetStaticHostname", hostname);
if (r < 0)
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
r = set_simple_string_internal(bus, &error, "static hostname", "SetStaticHostname", hostname);
if (r < 0) {
if (implicit &&
sd_bus_error_has_names(&error,
BUS_ERROR_FILE_IS_PROTECTED,
BUS_ERROR_READ_ONLY_FILESYSTEM)) {
show_hint = true;
ret = r;
} else
return r;
}
}
if (arg_transient) {
r = set_simple_string(bus, "SetHostname", hostname);
r = set_simple_string(bus, "transient hostname", "SetHostname", hostname);
if (r < 0)
return r;
}
return 0;
if (show_hint)
log_info("Hint: use --transient option when /etc/machine-info or /etc/hostname cannot be modified (e.g. located in read-only filesystem).");
return ret;
}
static int set_icon_name(int argc, char **argv, void *userdata) {
return set_simple_string(userdata, "SetIconName", argv[1]);
return set_simple_string(userdata, "icon", "SetIconName", argv[1]);
}
static int set_chassis(int argc, char **argv, void *userdata) {
return set_simple_string(userdata, "SetChassis", argv[1]);
return set_simple_string(userdata, "chassis", "SetChassis", argv[1]);
}
static int set_deployment(int argc, char **argv, void *userdata) {
return set_simple_string(userdata, "SetDeployment", argv[1]);
return set_simple_string(userdata, "deployment", "SetDeployment", argv[1]);
}
static int set_location(int argc, char **argv, void *userdata) {
return set_simple_string(userdata, "SetLocation", argv[1]);
return set_simple_string(userdata, "location", "SetLocation", argv[1]);
}
static int help(void) {

View File

@ -367,20 +367,41 @@ static int context_update_kernel_hostname(
return r; /* 0 if no change, 1 if something was done */
}
static void unset_statp(struct stat **p) {
if (!*p)
return;
**p = (struct stat) {};
}
static int context_write_data_static_hostname(Context *c) {
_cleanup_(unset_statp) struct stat *s = NULL;
int r;
assert(c);
/* Make sure that if we fail here, we invalidate the cached information, since it was updated
* already, even if we can't make it hit the disk. */
s = &c->etc_hostname_stat;
if (isempty(c->data[PROP_STATIC_HOSTNAME])) {
if (unlink("/etc/hostname") < 0)
return errno == ENOENT ? 0 : -errno;
if (unlink("/etc/hostname") < 0 && errno != ENOENT)
return -errno;
TAKE_PTR(s);
return 0;
}
return write_string_file_atomic_label("/etc/hostname", c->data[PROP_STATIC_HOSTNAME]);
r = write_string_file_atomic_label("/etc/hostname", c->data[PROP_STATIC_HOSTNAME]);
if (r < 0)
return r;
TAKE_PTR(s);
return 0;
}
static int context_write_data_machine_info(Context *c) {
_cleanup_(unset_statp) struct stat *s = NULL;
static const char * const name[_PROP_MAX] = {
[PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME",
[PROP_ICON_NAME] = "ICON_NAME",
@ -388,12 +409,15 @@ static int context_write_data_machine_info(Context *c) {
[PROP_DEPLOYMENT] = "DEPLOYMENT",
[PROP_LOCATION] = "LOCATION",
};
_cleanup_strv_free_ char **l = NULL;
int r;
assert(c);
/* Make sure that if we fail here, we invalidate the cached information, since it was updated
* already, even if we can't make it hit the disk. */
s = &c->etc_machine_info_stat;
r = load_env_file(NULL, "/etc/machine-info", &l);
if (r < 0 && r != -ENOENT)
return r;
@ -421,13 +445,19 @@ static int context_write_data_machine_info(Context *c) {
}
if (strv_isempty(l)) {
if (unlink("/etc/machine-info") < 0)
return errno == ENOENT ? 0 : -errno;
if (unlink("/etc/machine-info") < 0 && errno != ENOENT)
return -errno;
TAKE_PTR(s);
return 0;
}
return write_env_file_label("/etc/machine-info", l);
r = write_env_file_label("/etc/machine-info", l);
if (r < 0)
return r;
TAKE_PTR(s);
return 0;
}
static int property_get_hardware_vendor(
@ -760,13 +790,17 @@ static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = free_and_strdup(&c->data[PROP_STATIC_HOSTNAME], name);
r = free_and_strdup_warn(&c->data[PROP_STATIC_HOSTNAME], name);
if (r < 0)
return r;
r = context_write_data_static_hostname(c);
if (r < 0) {
log_error_errno(r, "Failed to write static hostname: %m");
if (ERRNO_IS_PRIVILEGE(r))
return sd_bus_error_set(error, BUS_ERROR_FILE_IS_PROTECTED, "Not allowed to update /etc/hostname.");
if (r == -EROFS)
return sd_bus_error_set(error, BUS_ERROR_READ_ONLY_FILESYSTEM, "/etc/hostname is in a read-only filesystem.");
return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %m");
}
@ -836,13 +870,17 @@ static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_mess
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = free_and_strdup(&c->data[prop], name);
r = free_and_strdup_warn(&c->data[prop], name);
if (r < 0)
return r;
r = context_write_data_machine_info(c);
if (r < 0) {
log_error_errno(r, "Failed to write machine info: %m");
if (ERRNO_IS_PRIVILEGE(r))
return sd_bus_error_set(error, BUS_ERROR_FILE_IS_PROTECTED, "Not allowed to update /etc/machine-info.");
if (r == -EROFS)
return sd_bus_error_set(error, BUS_ERROR_READ_ONLY_FILESYSTEM, "/etc/machine-info is in a read-only filesystem.");
return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %m");
}

View File

@ -16,14 +16,12 @@
#include "strv.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
_cleanup_fclose_ FILE *dev_null = NULL;
RemoteServer s = {};
char name[] = "/tmp/fuzz-journal-remote.XXXXXX.journal";
int fdin;
void *mem;
int fdin; /* will be closed by journal_remote handler after EOF */
_cleanup_(unlink_tempfilep) char name[] = "/tmp/fuzz-journal-remote.XXXXXX.journal";
_cleanup_close_ int fdout = -1;
sd_journal *j;
OutputMode mode;
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
RemoteServer s = {};
int r;
if (size <= 2)
@ -32,36 +30,54 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (!getenv("SYSTEMD_LOG_LEVEL"))
log_set_max_level(LOG_CRIT);
assert_se((fdin = memfd_new_and_map("fuzz-journal-remote", size, &mem)) >= 0);
fdin = memfd_new_and_map("fuzz-journal-remote", size, &mem);
if (fdin < 0)
return log_error_errno(fdin, "memfd_new_and_map() failed: %m");
memcpy(mem, data, size);
assert_se(munmap(mem, size) == 0);
fdout = mkostemps(name, STRLEN(".journal"), O_CLOEXEC);
assert_se(fdout >= 0);
if (fdout < 0)
return log_error_errno(errno, "mkostemps() failed: %m");
/* In */
assert_se(journal_remote_server_init(&s, name, JOURNAL_WRITE_SPLIT_NONE, false, false) >= 0);
assert_se(journal_remote_add_source(&s, fdin, (char*) "fuzz-data", false) > 0);
while (s.active) {
r = journal_remote_handle_raw_source(NULL, fdin, 0, &s);
assert_se(r >= 0);
r = journal_remote_server_init(&s, name, JOURNAL_WRITE_SPLIT_NONE, false, false);
if (r < 0) {
assert_se(IN_SET(r, -ENOMEM, -EMFILE, -ENFILE));
return r;
}
r = journal_remote_add_source(&s, fdin, (char*) "fuzz-data", false);
if (r < 0) {
safe_close(fdin);
return r;
}
assert(r > 0);
while (s.active)
assert_se(journal_remote_handle_raw_source(NULL, fdin, 0, &s) >= 0);
journal_remote_server_destroy(&s);
assert_se(close(fdin) < 0 && errno == EBADF); /* Check that the fd is closed already */
/* Out */
r = sd_journal_open_files(&j, (const char**) STRV_MAKE(name), 0);
assert_se(r >= 0);
if (r < 0) {
assert_se(IN_SET(r, -ENOMEM, -EMFILE, -ENFILE));
return r;
}
if (getenv_bool("SYSTEMD_FUZZ_OUTPUT") <= 0)
assert_se(dev_null = fopen("/dev/null", "we"));
_cleanup_fclose_ FILE *dev_null = NULL;
if (getenv_bool("SYSTEMD_FUZZ_OUTPUT") <= 0) {
dev_null = fopen("/dev/null", "we");
if (!dev_null)
return log_error_errno(errno, "fopen(\"/dev/null\") failed: %m");
}
for (mode = 0; mode < _OUTPUT_MODE_MAX; mode++) {
for (OutputMode mode = 0; mode < _OUTPUT_MODE_MAX; mode++) {
if (!dev_null)
log_info("/* %s */", output_mode_to_string(mode));
r = show_journal(dev_null ?: stdout, j, mode, 0, 0, -1, 0, NULL);
@ -71,8 +87,5 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
assert_se(r >= 0);
}
sd_journal_close(j);
unlink(name);
return 0;
}

View File

@ -101,6 +101,8 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
SD_BUS_ERROR_MAP(BUS_ERROR_TRANSFER_IN_PROGRESS, EBUSY),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_PRODUCT_UUID, EOPNOTSUPP),
SD_BUS_ERROR_MAP(BUS_ERROR_FILE_IS_PROTECTED, EACCES),
SD_BUS_ERROR_MAP(BUS_ERROR_READ_ONLY_FILESYSTEM, EROFS),
SD_BUS_ERROR_MAP(BUS_ERROR_SPEED_METER_INACTIVE, EOPNOTSUPP),
SD_BUS_ERROR_MAP(BUS_ERROR_UNMANAGED_INTERFACE, EOPNOTSUPP),

View File

@ -81,6 +81,8 @@
#define BUS_ERROR_TRANSFER_IN_PROGRESS "org.freedesktop.import1.TransferInProgress"
#define BUS_ERROR_NO_PRODUCT_UUID "org.freedesktop.hostname1.NoProductUUID"
#define BUS_ERROR_FILE_IS_PROTECTED "org.freedesktop.hostname1.FileIsProtected"
#define BUS_ERROR_READ_ONLY_FILESYSTEM "org.freedesktop.hostname1.ReadOnlyFilesystem"
#define BUS_ERROR_SPEED_METER_INACTIVE "org.freedesktop.network1.SpeedMeterInactive"
#define BUS_ERROR_UNMANAGED_INTERFACE "org.freedesktop.network1.UnmanagedInterface"
@ -100,7 +102,8 @@
#define BUS_ERROR_LOW_PASSWORD_QUALITY "org.freedesktop.home1.LowPasswordQuality"
#define BUS_ERROR_BAD_PASSWORD_AND_NO_TOKEN "org.freedesktop.home1.BadPasswordAndNoToken"
#define BUS_ERROR_TOKEN_PIN_NEEDED "org.freedesktop.home1.TokenPinNeeded"
#define BUS_ERROR_TOKEN_PROTECTED_AUTHENTICATION_PATH_NEEDED "org.freedesktop.home1.TokenProtectedAuthenticationPathNeeded"
#define BUS_ERROR_TOKEN_PROTECTED_AUTHENTICATION_PATH_NEEDED \
"org.freedesktop.home1.TokenProtectedAuthenticationPathNeeded"
#define BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED "org.freedesktop.home1.TokenUserPresenceNeeded"
#define BUS_ERROR_TOKEN_ACTION_TIMEOUT "org.freedesktop.home1.TokenActionTimeout"
#define BUS_ERROR_TOKEN_PIN_LOCKED "org.freedesktop.home1.TokenPinLocked"

View File

@ -9,6 +9,7 @@
#include "netlink-util.h"
#include "networkd-address-pool.h"
#include "networkd-address.h"
#include "networkd-ipv6-proxy-ndp.h"
#include "networkd-manager.h"
#include "networkd-network.h"
#include "parse-util.h"
@ -911,6 +912,7 @@ int address_configure(
static int static_address_ready_callback(Address *address) {
Address *a;
Link *link;
int r;
assert(address);
assert(address->link);
@ -935,6 +937,10 @@ static int static_address_ready_callback(Address *address) {
link->addresses_ready = true;
r = link_set_ipv6_proxy_ndp_addresses(link);
if (r < 0)
return r;
return link_set_routes(link);
}
@ -1059,6 +1065,11 @@ int link_set_addresses(Link *link) {
if (link->address_messages == 0) {
link->addresses_configured = true;
link->addresses_ready = true;
r = link_set_ipv6_proxy_ndp_addresses(link);
if (r < 0)
return r;
r = link_set_routes(link);
if (r < 0)
return r;

View File

@ -29,7 +29,6 @@
#include "networkd-dhcp6.h"
#include "networkd-fdb.h"
#include "networkd-ipv4ll.h"
#include "networkd-ipv6-proxy-ndp.h"
#include "networkd-link-bus.h"
#include "networkd-link.h"
#include "networkd-lldp-tx.h"
@ -2036,10 +2035,6 @@ int link_configure(Link *link) {
if (r < 0)
return r;
r = link_set_ipv6_proxy_ndp_addresses(link);
if (r < 0)
return r;
r = link_set_mac(link);
if (r < 0)
return r;

View File

@ -244,7 +244,7 @@ static int boot_loader_read_conf(const char *path, BootConfig *config) {
}
static int boot_entry_compare(const BootEntry *a, const BootEntry *b) {
return str_verscmp(a->id, b->id);
return strverscmp_improved(a->id, b->id);
}
static int boot_entries_find(

View File

@ -247,7 +247,7 @@ static int condition_test_kernel_version(Condition *c, char **env) {
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unexpected end of expression: %s", p);
}
r = test_order(str_verscmp(u.release, s), order);
r = test_order(strverscmp_improved(u.release, s), order);
} else
/* No prefix? Then treat as glob string */
r = fnmatch(s, u.release, 0) == 0;

View File

@ -2214,8 +2214,8 @@ int dissected_image_acquire_metadata(DissectedImage *m) {
[META_HOSTNAME] = "/etc/hostname\0",
[META_MACHINE_ID] = "/etc/machine-id\0",
[META_MACHINE_INFO] = "/etc/machine-info\0",
[META_OS_RELEASE] = "/etc/os-release\0"
"/usr/lib/os-release\0",
[META_OS_RELEASE] = ("/etc/os-release\0"
"/usr/lib/os-release\0"),
};
_cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL;

View File

@ -1 +0,0 @@
../boot/efi/loader-features.h

View File

@ -233,4 +233,4 @@ static const char* const hostname_source_table[] = {
[HOSTNAME_FALLBACK] = "fallback",
};
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(hostname_source, HostnameSource);
DEFINE_STRING_TABLE_LOOKUP(hostname_source, HostnameSource);

View File

@ -11,7 +11,9 @@ typedef enum HostnameSource {
_HOSTNAME_INVALID = -1,
} HostnameSource;
const char* hostname_source_to_string(HostnameSource source);
const char* hostname_source_to_string(HostnameSource source) _const_;
HostnameSource hostname_source_from_string(const char *str) _pure_;
int sethostname_idempotent(const char *s);
int shorten_overlong(const char *s, char **ret);

View File

@ -89,7 +89,6 @@ shared_sources = files('''
dns-domain.h
dropin.c
dropin.h
efi-loader-features.h
efi-loader.c
efi-loader.h
enable-mempool.c

View File

@ -395,9 +395,9 @@ static int merge_hierarchy(
return 1;
}
static int strverscmpp(char *const* a, char *const* b) {
/* usable in qsort() for sorting a string array with strverscmp() */
return strverscmp(*a, *b);
static int strverscmp_improvedp(char *const* a, char *const* b) {
/* usable in qsort() for sorting a string array with strverscmp_improved() */
return strverscmp_improved(*a, *b);
}
static int validate_version(
@ -623,8 +623,8 @@ static int merge_subprocess(Hashmap *images, const char *workspace) {
return 0;
}
/* Order by version sort (i.e. libc strverscmp()) */
typesafe_qsort(extensions, n_extensions, strverscmpp);
/* Order by version sort with strverscmp_improved() */
typesafe_qsort(extensions, n_extensions, strverscmp_improvedp);
buf = strv_join(extensions, "', '");
if (!buf)

View File

@ -886,6 +886,84 @@ static void test_string_contains_word(void) {
assert_se(!string_contains_word("a:b:cc", ":#", ":cc"));
}
static void test_strverscmp_improved_one(const char *newer, const char *older) {
log_info("/* %s(%s, %s) */", __func__, strnull(newer), strnull(older));
assert_se(strverscmp_improved(newer, newer) == 0);
assert_se(strverscmp_improved(newer, older) > 0);
assert_se(strverscmp_improved(older, newer) < 0);
assert_se(strverscmp_improved(older, older) == 0);
}
static void test_strverscmp_improved(void) {
static const char * const versions[] = {
"",
"~1",
"ab",
"abb",
"abc",
"0001",
"002",
"12",
"122",
"122.9",
"123~rc1",
"123",
"123-a",
"123-a.1",
"123-a1",
"123-a1.1",
"123-3",
"123-3.1",
"123^patch1",
"123^1",
"123.a-1"
"123.1-1",
"123a-1",
"124",
NULL,
};
const char * const *p, * const *q;
STRV_FOREACH(p, versions)
STRV_FOREACH(q, p + 1)
test_strverscmp_improved_one(*q, *p);
test_strverscmp_improved_one("123.45-67.89", "123.45-67.88");
test_strverscmp_improved_one("123.45-67.89a", "123.45-67.89");
test_strverscmp_improved_one("123.45-67.89", "123.45-67.ab");
test_strverscmp_improved_one("123.45-67.89", "123.45-67.9");
test_strverscmp_improved_one("123.45-67.89", "123.45-67");
test_strverscmp_improved_one("123.45-67.89", "123.45-66.89");
test_strverscmp_improved_one("123.45-67.89", "123.45-9.99");
test_strverscmp_improved_one("123.45-67.89", "123.42-99.99");
test_strverscmp_improved_one("123.45-67.89", "123-99.99");
/* '~' : pre-releases */
test_strverscmp_improved_one("123.45-67.89", "123~rc1-99.99");
test_strverscmp_improved_one("123-45.67.89", "123~rc1-99.99");
test_strverscmp_improved_one("123~rc2-67.89", "123~rc1-99.99");
test_strverscmp_improved_one("123^aa2-67.89", "123~rc1-99.99");
test_strverscmp_improved_one("123aa2-67.89", "123~rc1-99.99");
/* '-' : separator between version and release. */
test_strverscmp_improved_one("123.45-67.89", "123-99.99");
test_strverscmp_improved_one("123^aa2-67.89", "123-99.99");
test_strverscmp_improved_one("123aa2-67.89", "123-99.99");
/* '^' : patch releases */
test_strverscmp_improved_one("123.45-67.89", "123^45-67.89");
test_strverscmp_improved_one("123^aa2-67.89", "123^aa1-99.99");
test_strverscmp_improved_one("123aa2-67.89", "123^aa2-67.89");
/* '.' : point release */
test_strverscmp_improved_one("123aa2-67.89", "123.aa2-67.89");
test_strverscmp_improved_one("123.ab2-67.89", "123.aa2-67.89");
/* invalid characters */
assert_se(strverscmp_improved("123_aa2-67.89", "123aa+2-67.89") == 0);
}
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
@ -923,6 +1001,7 @@ int main(int argc, char *argv[]) {
test_string_extract_line();
test_string_contains_word_strv();
test_string_contains_word();
test_strverscmp_improved();
return 0;
}

View File

@ -37,17 +37,17 @@ static void test_xdg_format_exec_start(void) {
}
static const char* const xdg_desktop_file[] = {
"[Desktop Entry]\n"
("[Desktop Entry]\n"
"Exec\t =\t /bin/sleep 100\n" /* Whitespace Before/After = must be ignored */
"OnlyShowIn = A;B;\n"
"NotShowIn=C;;D\\\\\\;;E\n", /* "C", "", "D\;", "E" */
"NotShowIn=C;;D\\\\\\;;E\n"), /* "C", "", "D\;", "E" */
"[Desktop Entry]\n"
("[Desktop Entry]\n"
"Exec=a\n"
"Exec=b\n",
"Exec=b\n"),
"[Desktop Entry]\n"
"Hidden=\t true\n",
("[Desktop Entry]\n"
"Hidden=\t true\n"),
};
static void test_xdg_desktop_parse(unsigned i, const char *s) {

View File

@ -1952,7 +1952,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertRegex(output, 'local fdde:11:44::1 proto kernel metric 0 pref medium')
self.assertRegex(output, 'local fdde:11:55::1 proto kernel metric 0 pref medium')
self.assertRegex(output, 'fe80::/64 proto kernel metric 256 pref medium')
self.assertRegex(output, 'ff00::/8 metric 256 pref medium')
self.assertRegex(output, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium')
print()
@ -1984,7 +1984,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertRegex(output, 'local fdde:12:33::1 proto kernel metric 0 pref medium')
self.assertRegex(output, 'local fdde:12:44::1 proto kernel metric 0 pref medium')
self.assertRegex(output, 'local fdde:12:55::1 proto kernel metric 0 pref medium')
self.assertRegex(output, 'ff00::/8 metric 256 pref medium')
self.assertRegex(output, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium')
def test_configure_without_carrier(self):
copy_unit_to_networkd_unit_path('11-dummy.netdev')
@ -3308,7 +3308,7 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities):
print('### ip -6 route list table all dev bridge99')
output = check_output('ip -6 route list table all dev bridge99')
print(output)
self.assertRegex(output, 'ff00::/8 table local metric 256 pref medium')
self.assertRegex(output, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
self.assertEqual(call('ip link del test1'), 0)
@ -3327,7 +3327,7 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities):
print('### ip -6 route list table all dev bridge99')
output = check_output('ip -6 route list table all dev bridge99')
print(output)
self.assertRegex(output, 'ff00::/8 table local metric 256 (linkdown )?pref medium')
self.assertRegex(output, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
def test_bridge_configure_without_carrier(self):
copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-configure-without-carrier.network',