1
0
mirror of https://github.com/systemd/systemd synced 2026-03-31 20:24:50 +02:00

Compare commits

...

27 Commits

Author SHA1 Message Date
Bastian Almendras
a0d1dc662a
hwdb: add entry for Acer Switch One 10 (SW1-011) (#39716)
Add the correct rotation for Acer Switch One 10 (SW1-011)
2025-11-14 04:33:47 +09:00
Antonio Alvarez Feijoo
3eabddbe9f gpt-auto-generator: fix typo in crypttab option name
Spotted while debugging a ParticleOS build:

```
Nov 13 14:44:32 localhost systemd-cryptsetup[591]: Encountered unknown /etc/crypttab option 'tpm2-measure-slot-nvpcr=cryptsetup', ignoring.
```

Follow-up for e5a2e7866572614e66cbf6c1d3969128562d9552
2025-11-14 03:50:15 +09:00
Yu Watanabe
aec0e63a4f musl: test: several random fixlets for unit tests 2025-11-14 03:29:21 +09:00
Yu Watanabe
be33b202e6
core: record transactions that have seen ordering cycles and expose them via IPC (#39210)
Closes #3829.
2025-11-14 00:41:46 +09:00
Yu Watanabe
3db66ed388
Make systemd stdio bridge quiet (#39718) 2025-11-14 00:39:15 +09:00
Yu Watanabe
1abe8dd9eb
efivarfs readv() size fixes and more (#39715)
Fixes: #39695
2025-11-14 00:38:29 +09:00
Yu Watanabe
32d1bed50b
tree-wide: assorted fixes/workarounds for supporting musl (#39687) 2025-11-14 00:16:50 +09:00
Daan De Meyer
59a81bbb80 sd-bus: Pass --user and --quiet to systemd-stdio-bridge if local
If we're switching users but not entering a container, then we can
assume that new switches for systemd-stdio-bridge are available, so
make use of them in that case.
2025-11-13 14:45:51 +01:00
Daan De Meyer
dcf8bdf01d stdio-bridge: Fix --user
If --user was specified we would still try to use the system bus
address.
2025-11-13 14:45:51 +01:00
Daan De Meyer
8bb6f4f164 stdio-bridge: Add --quiet option
When we use stdio-bridge via sd-bus to connect to a bus of a different
user, container or host, stdio-bridge should not log at error level but
at debug level as it's invoked by the sd-bus library and sd-bus should
generally not log above debug level.

We can't actually use the --quiet option yet as that would break connecting
to hosts running older versions of systemd but let's already add the option
now in preparation for a brighter future.
2025-11-13 14:45:51 +01:00
Daan De Meyer
0d91a204cb bus-wait-for-jobs: Make sure we always debug log
If we're not logging at a higher priority level, let's still log
at debug log level to help with debugging.
2025-11-13 14:45:51 +01:00
Daan De Meyer
164fc38888 shared: Forward declare InstallChange in shared-forward.h 2025-11-13 14:41:25 +01:00
Lennart Poettering
f5452477d4 tree-wide: fix lseek() parameter order
The offset must be specified first, 'whence' second. Fix that.

Except for one case this fix doesn't actually fix any real bug, since
SEEK_SET is defined as 0 anyway, hence the swapped arguments have no
effect.

The one exception is the MTD smartmedia code, which I guess indicates
that noone has been using that hw anymore in a long time?
2025-11-13 14:19:29 +01:00
Lennart Poettering
dbc25d84ae efivars: seek back to beginning in each efi_get_variable() loop
We try to read again from the beginning, hence let's seek back.
Apparently efivarfs doesn't strictly require this, but it's really weird
that it doesn't.
2025-11-13 14:19:29 +01:00
Lennart Poettering
40cb2aa4f8 efivars: validate we are actually talking about a regular file
We already have the stat data, let's actually check if things are
alright before relying on .st_size
2025-11-13 14:19:29 +01:00
Lennart Poettering
ab69a04600 efivars: fix size checks in efi_get_variable()
writev() returns the full size, not just the payload size, hence always
add sizeof(attr) where necessary.

Let's also change a couple of "4" into sizeof(attr) all over the place,
to make clear what they are about.

Fixes: #39695
Follow-up for: 9db9d6806e398465a6366dfc5bdde2e24338ac29
2025-11-13 14:19:29 +01:00
Lennart Poettering
88e26303ce efivars: don't bother with realloc() if we have no interest in the old data
We shouldn't ask glibc to keep the old data around (which realloc() is
about), given we overwrite it entirely anyway. Let's hence speed things
up here, and allow glibc to just allocate a new block for us (and
shorten the code a bit)
2025-11-13 12:37:08 +01:00
Yu Watanabe
a580dd4e53 musl: format-util: use %llu for formatting rlim_t
glibc uses uint32_t or uint64_t for rlim_t, while musl uses unsigned long long.
2025-11-13 08:02:05 +09:00
Yu Watanabe
4b774c740b musl: build-path: fix reading DT_RUNPATH or DT_RPATH
musl records DT_STRTAB as offset, rather than address. So, need to add
obtained bias to read runpath or rpath.
2025-11-13 08:02:05 +09:00
Yu Watanabe
3866923a68 musl: core: there is one less usable signal when built with musl
musl internally reserves one more signal, hence we can only use 29
signals.
2025-11-13 08:02:05 +09:00
Yu Watanabe
ebbc0ea7fd musl: avoid multiple evaluations in CPU_ISSET_S() macro
musl's CPU_ISSET_S() macro does not avoid multiple evaluations, and it
only accepts simple variable or constant.

Fixes the following error.
```
../src/shared/cpu-set-util.c: In function ‘cpu_set_to_mask_string’:
../src/shared/cpu-set-util.c:101:41: warning: operation on ‘i’ may be undefined [-Werror=sequence-point]
  101 |                         if (CPU_ISSET_S(--i, c->allocated, c->set))
      |                                         ^
```
2025-11-13 08:02:05 +09:00
Yu Watanabe
5bb9063505 musl: hostname-util: introduce LINUX_HOST_NAME_MAX
glibc defines HOST_NAME_MAX as 64 and our code rely on that, but musl
defines the constant as 255. Let's provide our own definition for the
maximum length.
2025-11-13 08:02:05 +09:00
Mike Yuan
397681405a
TEST-03-JOBS: add test for TransactionsWithOrderingCycle 2025-11-12 23:47:39 +01:00
Mike Yuan
58686034eb
core: expose transactions with ordering cycle
Closes #3829
Alternative to #35417

I don't think the individual "WasOnDependencyCycle" attrs on units
are particularly helpful and comprehensible, as it's really about
the dep relationship between them. And as discussed, the dependency
cycle is not something persistent, rather local to the currently
loaded set of units and shall be reset with daemon-reload (see also
https://github.com/systemd/systemd/issues/35642#issuecomment-2591296586).

Hence, let's report system state as degraded and point users to
the involved transactions when ordering cycles are encountered instead.
Combined with log messages added in 6912eb315fabe0bbf25593ab897265fa79a7e24b
it should achieve the goal of making ordering cycles more observable,
while avoiding all sorts of subtle bookkeeping in the service manager.
The degraded state can be reset via the existing ResetFailed() manager-wide
method.
2025-11-12 23:47:39 +01:00
Mike Yuan
d3da74696b
core: record transactions that have seen ordering cycles 2025-11-12 23:47:39 +01:00
Mike Yuan
0d9e79d5ca
core/transaction: assign unique ids to transactions and encode them in log
Preparation for later commits, but I think this one makes
a ton of sense on its own. When debug logging is enabled
it's otherwise difficult to dig up the portion of journal
for transaction construction.
2025-11-12 23:47:38 +01:00
Mike Yuan
7ca94ff4b1
core/manager-serialize: minor coding style cleanups 2025-11-12 23:47:38 +01:00
41 changed files with 446 additions and 200 deletions

View File

@ -938,11 +938,12 @@ Defined-By: systemd
Support: %SUPPORT_URL%
Documentation: man:systemd(1)
A unit transaction was initiated that contains an ordering cycle, i.e. some
unit that was requested to be started (either directly, or indirectly due to a
requirement dependency such as Wants= or Requires=) is ordered before some
other unit (via After=/Before=), but that latter unit is also ordered before
the former by some dependency (either directly or indirectly).
A unit transaction (with ID @TRANSACTION_ID@) was initiated that contains
an ordering cycle, i.e. some unit that was requested to be started
(either directly, or indirectly due to a requirement dependency such as
Wants= or Requires=) is ordered before some other unit (via After=/Before=),
but that latter unit is also ordered before the former by some dependency
(either directly or indirectly).
Ordering cycles consist of at least two units, but might involve many
more. They generally indicate a bug in the unit definitions, as a unit

View File

@ -103,6 +103,9 @@ sensor:modalias:acpi:SMO8500:*:dmi:*Acer*:pnOneS1002:*
sensor:modalias:acpi:KIOX0009*:dmi:*:svnAcer:pnOneS1003:*
ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
sensor:modalias:acpi:KIOX000A*:dmi:*:svnAcer:pnSwitchOneSW1-011:*
ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
sensor:modalias:acpi:BOSC0200*:dmi:*:svnAcer*:pnSwitchSW312-31:*
ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1

View File

@ -413,6 +413,8 @@ node /org/freedesktop/systemd1 {
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly u NFailedJobs = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly at TransactionsWithOrderingCycle = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly d Progress = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly as Environment = ['...', ...];
@ -1103,6 +1105,8 @@ node /org/freedesktop/systemd1 {
<variablelist class="dbus-property" generated="True" extra-ref="NFailedJobs"/>
<variablelist class="dbus-property" generated="True" extra-ref="TransactionsWithOrderingCycle"/>
<variablelist class="dbus-property" generated="True" extra-ref="Progress"/>
<variablelist class="dbus-property" generated="True" extra-ref="Environment"/>
@ -1809,6 +1813,9 @@ node /org/freedesktop/systemd1 {
<para><varname>NFailedJobs</varname> encodes how many jobs have ever failed in total.</para>
<para><varname>TransactionsWithOrderingCycle</varname> encodes IDs of transactions that encountered
ordering cycle.</para>
<para><varname>Progress</varname> encodes boot progress as a floating point value between 0.0 and
1.0. This value begins at 0.0 at early-boot and ends at 1.0 when boot is finished and is based on the
number of executed and queued jobs. After startup, this field is always 1.0 indicating a finished
@ -12465,6 +12472,7 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
<para><varname>DefaultRestrictSUIDSGID</varname>,
<function>RemoveSubgroupFromUnit()</function>, and
<function>KillUnitSubgroup()</function> were added in version 258.</para>
<para><varname>TransactionsWithOrderingCycle</varname> was added in version 259.</para>
</refsect2>
<refsect2>
<title>Unit Objects</title>

View File

@ -225,8 +225,8 @@ Sun 2017-02-26 20:57:49 EST 2h 3min left Sun 2017-02-26 11:56:36 EST 6h ago
<listitem>
<para>Check whether any of the specified units is in the "failed" state. If no unit is specified,
check whether there are any failed units, which corresponds to the <literal>degraded</literal> state
returned by <command>is-system-running</command>. Returns an exit code <constant>0</constant>
check whether there are any failed units or ordering cycles, which corresponds to the <literal>degraded</literal>
state returned by <command>is-system-running</command>. Returns an exit code <constant>0</constant>
if at least one has failed, non-zero otherwise. Unless <option>--quiet</option> is specified, this
will also print the current unit or system state to standard output.</para>

View File

@ -69,6 +69,15 @@
<xi:include href="version-info.xml" xpointer="v251"/></listitem>
</varlistentry>
<varlistentry>
<term><option>-q</option></term>
<term><option>--quiet</option></term>
<listitem><para>Suppresses error logging on failure.</para>
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>

View File

@ -34,11 +34,11 @@ static int get_runpath_from_dynamic(const ElfW(Dyn) *d, ElfW(Addr) bias, const c
break;
case DT_STRTAB:
/* On MIPS and RISC-V DT_STRTAB records an offset, not a valid address, so it has to be adjusted
* using the bias calculated earlier. */
/* On MIPS, RISC-V, or with musl, DT_STRTAB records an offset, not a valid address,
* so it has to be adjusted using the bias calculated earlier. */
if (d->d_un.d_val != 0)
strtab = (const char *) ((uintptr_t) d->d_un.d_val
#if defined(__mips__) || defined(__riscv)
#if defined(__mips__) || defined(__riscv) || !defined(__GLIBC__)
+ bias
#endif
);

View File

@ -14,6 +14,7 @@
#include "io-util.h"
#include "log.h"
#include "memory-util.h"
#include "stat-util.h"
#include "string-util.h"
#include "time-util.h"
#include "utf8.h"
@ -32,6 +33,7 @@ int efi_get_variable(
void **ret_value,
size_t *ret_size) {
int r;
usec_t begin = 0; /* Unnecessary initialization to appease gcc */
assert(variable);
@ -66,13 +68,16 @@ int efi_get_variable(
if (fstat(fd, &st) < 0)
return log_debug_errno(errno, "fstat(\"%s\") failed: %m", p);
if (st.st_size == 0)
return log_debug_errno(SYNTHETIC_ERRNO(ENOENT),
"EFI variable %s is uncommitted", p);
if (st.st_size < 4)
return log_debug_errno(SYNTHETIC_ERRNO(ENODATA), "EFI variable %s is shorter than 4 bytes, refusing.", p);
if (st.st_size > 4*1024*1024 + 4)
return log_debug_errno(SYNTHETIC_ERRNO(E2BIG), "EFI variable %s is ridiculously large, refusing.", p);
r = stat_verify_regular(&st);
if (r < 0)
return log_debug_errno(r, "EFI variable '%s' is not a regular file, refusing: %m", p);
if (st.st_size == 0) /* for uncommited variables, see below */
return log_debug_errno(SYNTHETIC_ERRNO(ENOENT), "EFI variable '%s' is uncommitted", p);
if ((uint64_t) st.st_size < sizeof(attr))
return log_debug_errno(SYNTHETIC_ERRNO(ENODATA), "EFI variable '%s' is shorter than %zu bytes, refusing.", p, sizeof(attr));
if ((uint64_t) st.st_size > sizeof(attr) + 4 * U64_MB)
return log_debug_errno(SYNTHETIC_ERRNO(E2BIG), "EFI variable '%s' is ridiculously large, refusing.", p);
if (!ret_attribute && !ret_value) {
/* No need to read anything, return the reported size. */
@ -81,31 +86,37 @@ int efi_get_variable(
}
/* We want +1 for the read call, and +3 for the additional terminating bytes added below. */
char *t = realloc(buf, (size_t) st.st_size + MAX(1, 3));
if (!t)
free(buf);
buf = malloc((size_t) st.st_size - sizeof(attr) + CONST_MAX(1, 3));
if (!buf)
return -ENOMEM;
buf = t;
const struct iovec iov[] = {
struct iovec iov[] = {
{ &attr, sizeof(attr) },
{ buf, (size_t) st.st_size + 1 },
{ buf, (size_t) st.st_size - sizeof(attr) + 1 },
};
n = readv(fd, iov, 2);
assert(n <= st.st_size + 1);
if (n == st.st_size + 1)
/* We need to try again with a bigger buffer. */
continue;
if (n >= 0)
break;
log_debug_errno(errno, "Reading from \"%s\" failed: %m", p);
if (n < 0) {
if (errno != EINTR)
return -errno;
return log_debug_errno(errno, "Reading from '%s' failed: %m", p);
log_debug("Reading from '%s' failed with EINTR, retrying.", p);
} else if ((size_t) n == sizeof(attr) + st.st_size + 1)
/* We need to try again with a bigger buffer, the variable was apparently changed concurrently? */
log_debug("EFI variable '%s' larger than expected, retrying.", p);
else {
assert((size_t) n < sizeof(attr) + st.st_size + 1);
break;
}
if (try >= EFI_N_RETRIES_TOTAL)
return -EBUSY;
return log_debug_errno(SYNTHETIC_ERRNO(EBUSY), "Reading EFI variable '%s' failed even after %u tries, giving up.", p, try);
if (try >= EFI_N_RETRIES_NO_DELAY)
(void) usleep_safe(EFI_RETRY_DELAY);
/* Start from the beginning */
(void) lseek(fd, 0, SEEK_SET);
}
/* Unfortunately kernel reports EOF if there's an inconsistency between efivarfs var list and
@ -122,19 +133,21 @@ int efi_get_variable(
if (n == 0)
return log_debug_errno(SYNTHETIC_ERRNO(ENOENT),
"EFI variable %s is uncommitted", p);
if (n < 4)
if ((size_t) n < sizeof(attr))
return log_debug_errno(SYNTHETIC_ERRNO(EIO),
"Read %zi bytes from EFI variable %s, expected >= 4", n, p);
"Read %zi bytes from EFI variable %s, expected >= %zu", n, p, sizeof(attr));
size_t value_size = n - sizeof(attr);
if (ret_attribute)
*ret_attribute = attr;
if (ret_value) {
assert(buf);
/* Always NUL-terminate (3 bytes, to properly protect UTF-16, even if truncated in
* the middle of a character) */
buf[n - 4] = 0;
buf[n - 4 + 1] = 0;
buf[n - 4 + 2] = 0;
buf[value_size] = 0;
buf[value_size + 1] = 0;
buf[value_size + 2] = 0;
*ret_value = TAKE_PTR(buf);
}
@ -149,7 +162,7 @@ int efi_get_variable(
* with a smaller value. */
if (ret_size)
*ret_size = n - 4;
*ret_size = value_size;
return 0;
}

View File

@ -39,12 +39,18 @@ assert_cc(sizeof(gid_t) == sizeof(uint32_t));
# error Unknown timex member size
#endif
#if SIZEOF_RLIM_T == 8
#ifdef __GLIBC__
# if SIZEOF_RLIM_T == 8
# define RLIM_FMT "%" PRIu64
#elif SIZEOF_RLIM_T == 4
# elif SIZEOF_RLIM_T == 4
# define RLIM_FMT "%" PRIu32
#else
# else
# error Unknown rlim_t size
# endif
#else
/* Assume musl, and it unconditionally uses unsigned long long. */
assert_cc(SIZEOF_RLIM_T == 8);
# define RLIM_FMT "%llu"
#endif
#if SIZEOF_DEV_T == 8

View File

@ -94,8 +94,8 @@ bool hostname_is_valid(const char *s, ValidHostnameFlags flags) {
if (hyphen)
return false;
if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on Linux, but DNS allows domain names up to
* 255 characters */
/* Note that host name max is 64 on Linux, but DNS allows domain names up to 255 characters. */
if (p - s > (ssize_t) LINUX_HOST_NAME_MAX)
return false;
return true;
@ -107,7 +107,7 @@ char* hostname_cleanup(char *s) {
assert(s);
for (p = s, d = s, dot = hyphen = true; *p && d - s < HOST_NAME_MAX; p++)
for (p = s, d = s, dot = hyphen = true; *p && d - s < (ssize_t) LINUX_HOST_NAME_MAX; p++)
if (*p == '.') {
if (dot || hyphen)
continue;

View File

@ -4,6 +4,9 @@
#include "basic-forward.h"
#include "strv.h"
/* HOST_NAME_MAX should be 64 on linux, but musl uses the one by POSIX (255). */
#define LINUX_HOST_NAME_MAX CONST_MIN((size_t) HOST_NAME_MAX, (size_t) 64)
char* get_default_hostname_raw(void);
bool valid_ldh_char(char c) _const_;

View File

@ -410,12 +410,26 @@ TEST(startswith8) {
ASSERT_NULL(startswith8(NULL, ""));
}
#define TEST_FNMATCH_ONE(pattern, haystack, expect) \
#define TEST_FNMATCH_ONE_FULL(pattern, haystack, expect, skip_libc) \
({ \
if (!skip_libc) \
ASSERT_EQ(fnmatch(pattern, haystack, 0), expect ? 0 : FNM_NOMATCH); \
ASSERT_EQ(efi_fnmatch(u##pattern, u##haystack), expect); \
})
#define TEST_FNMATCH_ONE(pattern, haystack, expect) \
TEST_FNMATCH_ONE_FULL(pattern, haystack, expect, false)
#ifdef __GLIBC__
#define TEST_FNMATCH_ONE_MAY_SKIP_LIBC(pattern, haystack, expect) \
TEST_FNMATCH_ONE_FULL(pattern, haystack, expect, false)
#else
/* It seems musl is too strict in handling "[]" (or has a bug?). Anyway, let's skip some test cases when
* built with musl. The behavior of efi_fnmatch() does not need to match musl's fnmatch(). */
#define TEST_FNMATCH_ONE_MAY_SKIP_LIBC(pattern, haystack, expect) \
TEST_FNMATCH_ONE_FULL(pattern, haystack, expect, true)
#endif
TEST(efi_fnmatch) {
TEST_FNMATCH_ONE("", "", true);
TEST_FNMATCH_ONE("abc", "abc", true);
@ -447,18 +461,18 @@ TEST(efi_fnmatch) {
TEST_FNMATCH_ONE("[abc", "a", false);
TEST_FNMATCH_ONE("[][!] [][!] [][!]", "[ ] !", true);
TEST_FNMATCH_ONE("[]-] []-]", "] -", true);
TEST_FNMATCH_ONE("[1\\]] [1\\]]", "1 ]", true);
TEST_FNMATCH_ONE_MAY_SKIP_LIBC("[1\\]] [1\\]]", "1 ]", true);
TEST_FNMATCH_ONE("[$-\\+]", "&", true);
TEST_FNMATCH_ONE("[1-3A-C] [1-3A-C]", "2 B", true);
TEST_FNMATCH_ONE("[3-5] [3-5] [3-5]", "3 4 5", true);
TEST_FNMATCH_ONE("[f-h] [f-h] [f-h]", "f g h", true);
TEST_FNMATCH_ONE("[a-c-f] [a-c-f] [a-c-f] [a-c-f] [a-c-f]", "a b c - f", true);
TEST_FNMATCH_ONE("[a-c-f]", "e", false);
TEST_FNMATCH_ONE_MAY_SKIP_LIBC("[a-c-f] [a-c-f] [a-c-f] [a-c-f] [a-c-f]", "a b c - f", true);
TEST_FNMATCH_ONE_MAY_SKIP_LIBC("[a-c-f]", "e", false);
TEST_FNMATCH_ONE("[--0] [--0] [--0]", "- . 0", true);
TEST_FNMATCH_ONE("[+--] [+--] [+--]", "+ , -", true);
TEST_FNMATCH_ONE("[f-l]", "m", false);
TEST_FNMATCH_ONE("[b]", "z-a", false);
TEST_FNMATCH_ONE("[a\\-z]", "b", false);
TEST_FNMATCH_ONE_MAY_SKIP_LIBC("[a\\-z]", "b", false);
TEST_FNMATCH_ONE("?a*b[.-0]c", "/a/b/c", true);
TEST_FNMATCH_ONE("debian-*-*-*.*", "debian-jessie-2018-06-17-kernel-image-5.10.0-16-amd64.efi", true);
@ -674,8 +688,14 @@ TEST(xvasprintf_status) {
test_printf_one("string");
test_printf_one("%%-%%%%");
#ifdef __GLIBC__
test_printf_one("%p %p %32p %*p %*p", NULL, (void *) 0xF, &errno, 0, &saved_argc, 20, &saved_argv);
test_printf_one("%-10p %-32p %-*p %-*p", NULL, &errno, 0, &saved_argc, 20, &saved_argv);
#else
/* musl prints NULL as 0, while glibc and our implementation print it as (nil). */
test_printf_one("%p %32p %*p %*p", (void *) 0xF, &errno, 0, &saved_argc, 20, &saved_argv);
test_printf_one("%-32p %-*p %-*p", &errno, 0, &saved_argc, 20, &saved_argv);
#endif
test_printf_one("%c %3c %*c %*c %-8c", '1', '!', 0, 'a', 9, '_', '>');

View File

@ -455,6 +455,35 @@ static int property_get_oom_score_adjust(
return sd_bus_message_append(reply, "i", n);
}
static int property_get_transactions_with_cycle(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
Manager *m = ASSERT_PTR(userdata);
int r;
assert(bus);
assert(reply);
r = sd_bus_message_open_container(reply, 'a', "t");
if (r < 0)
return r;
uint64_t *id;
SET_FOREACH(id, m->transactions_with_cycle) {
r = sd_bus_message_append_basic(reply, 't', id);
if (r < 0)
return r;
}
return sd_bus_message_close_container(reply);
}
static int bus_get_unit_by_name(Manager *m, sd_bus_message *message, const char *name, Unit **ret_unit, sd_bus_error *error) {
Unit *u;
int r;
@ -2870,6 +2899,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_PROPERTY("NJobs", "u", property_get_hashmap_size, offsetof(Manager, jobs), 0),
SD_BUS_PROPERTY("NInstalledJobs", "u", bus_property_get_unsigned, offsetof(Manager, n_installed_jobs), 0),
SD_BUS_PROPERTY("NFailedJobs", "u", bus_property_get_unsigned, offsetof(Manager, n_failed_jobs), 0),
SD_BUS_PROPERTY("TransactionsWithOrderingCycle", "at", property_get_transactions_with_cycle, 0, 0),
SD_BUS_PROPERTY("Progress", "d", property_get_progress, 0, 0),
SD_BUS_PROPERTY("Environment", "as", property_get_environment, 0, 0),
SD_BUS_PROPERTY("ConfirmSpawn", "b", bus_property_get_bool, offsetof(Manager, confirm_spawn), SD_BUS_VTABLE_PROPERTY_CONST),

View File

@ -6633,7 +6633,7 @@ int config_parse_protect_hostname(
const char *colon = strchr(rvalue, ':');
if (colon) {
r = unit_full_printf_full(u, colon + 1, HOST_NAME_MAX, &h);
r = unit_full_printf_full(u, colon + 1, LINUX_HOST_NAME_MAX, &h);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to resolve unit specifiers in '%s', ignoring: %m", colon + 1);

View File

@ -92,6 +92,8 @@ int manager_serialize(
_cleanup_(manager_reloading_stopp) _unused_ Manager *reloading = manager_reloading_start(m);
(void) serialize_item_format(f, "last-transaction-id", "%" PRIu64, m->last_transaction_id);
(void) serialize_item_format(f, "current-job-id", "%" PRIu32, m->current_job_id);
(void) serialize_item_format(f, "n-installed-jobs", "%u", m->n_installed_jobs);
(void) serialize_item_format(f, "n-failed-jobs", "%u", m->n_failed_jobs);
@ -283,7 +285,7 @@ static void manager_deserialize_gid_refs_one(Manager *m, const char *value) {
int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
bool deserialize_varlink_sockets = false;
int r = 0;
int r;
assert(m);
assert(f);
@ -325,7 +327,15 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
if (r == 0) /* eof or end marker */
break;
if ((val = startswith(l, "current-job-id="))) {
if ((val = startswith(l, "last-transaction-id="))) {
uint64_t id;
if (safe_atou64(val, &id) < 0)
log_notice("Failed to parse last transaction id value '%s', ignoring.", val);
else
m->last_transaction_id = MAX(m->last_transaction_id, id);
} else if ((val = startswith(l, "current-job-id="))) {
uint32_t id;
if (safe_atou32(val, &id) < 0)
@ -350,22 +360,18 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
m->n_failed_jobs += n;
} else if ((val = startswith(l, "taint-logged="))) {
int b;
b = parse_boolean(val);
if (b < 0)
r = parse_boolean(val);
if (r < 0)
log_notice("Failed to parse taint-logged flag '%s', ignoring.", val);
else
m->taint_logged = m->taint_logged || b;
m->taint_logged = m->taint_logged || r;
} else if ((val = startswith(l, "service-watchdogs="))) {
int b;
b = parse_boolean(val);
if (b < 0)
r = parse_boolean(val);
if (r < 0)
log_notice("Failed to parse service-watchdogs flag '%s', ignoring.", val);
else
m->service_watchdogs = b;
m->service_watchdogs = r;
} else if ((val = startswith(l, "show-status-overridden="))) {
ShowStatus s;

View File

@ -526,8 +526,9 @@ static int manager_setup_signals(Manager *m) {
assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
/* We make liberal use of realtime signals here. On Linux/glibc we have 30 of them, between
* SIGRTMIN+0 ... SIGRTMIN+30 (aka SIGRTMAX). */
/* We make liberal use of realtime signals here. On Linux we have 29 of them, between
* SIGRTMIN+0 ... SIGRTMIN+29. The glibc has one more (SIGRTMAX is SIGRTMIN+30),
* but musl does not (SIGRTMAX is SIGRTMIN+29). */
assert_se(sigemptyset(&mask) == 0);
sigset_add_many(&mask,
@ -572,7 +573,7 @@ static int manager_setup_signals(Manager *m) {
SIGRTMIN+28, /* systemd: set log target to kmsg */
SIGRTMIN+29, /* systemd: set log target to syslog-or-kmsg (obsolete) */
/* ... one free signal here SIGRTMIN+30 ... */
/* ... one free signal here SIGRTMIN+30 (glibc only) ... */
-1);
assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
@ -1659,6 +1660,8 @@ static void manager_clear_jobs_and_units(Manager *m) {
m->n_running_jobs = 0;
m->n_installed_jobs = 0;
m->n_failed_jobs = 0;
m->transactions_with_cycle = set_free(m->transactions_with_cycle);
}
Manager* manager_free(Manager *m) {
@ -2153,14 +2156,16 @@ int manager_add_job_full(
if (mode == JOB_RESTART_DEPENDENCIES && type != JOB_START)
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "--job-mode=restart-dependencies is only valid for start.");
tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY, ++m->last_transaction_id);
if (!tr)
return -ENOMEM;
LOG_CONTEXT_PUSHF("TRANSACTION_ID=%" PRIu64, tr->id);
log_unit_debug(unit, "Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode));
type = job_type_collapse(type, unit);
tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY);
if (!tr)
return -ENOMEM;
r = transaction_add_job_and_dependencies(
tr,
type,
@ -2247,18 +2252,20 @@ int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name,
}
int manager_propagate_reload(Manager *m, Unit *unit, JobMode mode, sd_bus_error *e) {
int r;
_cleanup_(transaction_abort_and_freep) Transaction *tr = NULL;
int r;
assert(m);
assert(unit);
assert(mode < _JOB_MODE_MAX);
assert(mode != JOB_ISOLATE); /* Isolate is only valid for start */
tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY);
tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY, ++m->last_transaction_id);
if (!tr)
return -ENOMEM;
LOG_CONTEXT_PUSHF("TRANSACTION_ID=%" PRIu64, tr->id);
/* We need an anchor job */
r = transaction_add_job_and_dependencies(tr, JOB_NOP, unit, NULL, TRANSACTION_IGNORE_REQUIREMENTS|TRANSACTION_IGNORE_ORDER, e);
if (r < 0)
@ -3669,6 +3676,8 @@ void manager_reset_failed(Manager *m) {
HASHMAP_FOREACH(u, m->units)
unit_reset_failed(u);
m->transactions_with_cycle = set_free(m->transactions_with_cycle);
}
bool manager_unit_inactive_or_pending(Manager *m, const char *name) {
@ -4617,8 +4626,8 @@ ManagerState manager_state(Manager *m) {
return MANAGER_MAINTENANCE;
}
/* Are there any failed units? If so, we are in degraded mode */
if (!set_isempty(m->failed_units))
/* Are there any failed units or ordering cycles? If so, we are in degraded mode */
if (!set_isempty(m->failed_units) || !set_isempty(m->transactions_with_cycle))
return MANAGER_DEGRADED;
return MANAGER_RUNNING;

View File

@ -236,6 +236,11 @@ typedef struct Manager {
/* A set which contains all currently failed units */
Set *failed_units;
uint64_t last_transaction_id;
/* IDs of transactions that once encountered ordering cycle */
Set *transactions_with_cycle;
sd_event_source *run_queue_event_source;
char *notify_socket;

View File

@ -8,6 +8,7 @@
#include "bus-common-errors.h"
#include "bus-error.h"
#include "dbus-unit.h"
#include "hash-funcs.h"
#include "manager.h"
#include "set.h"
#include "slice.h"
@ -15,6 +16,8 @@
#include "strv.h"
#include "transaction.h"
#define CYCLIC_TRANSACTIONS_MAX 4096U
static bool job_matters_to_anchor(Job *job);
static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies);
@ -399,6 +402,16 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
LOG_MESSAGE_ID(SD_MESSAGE_UNIT_ORDERING_CYCLE_STR),
LOG_ITEM("%s", strempty(unit_ids)));
if (set_size(j->manager->transactions_with_cycle) >= CYCLIC_TRANSACTIONS_MAX)
log_warning("Too many transactions with ordering cycle, suppressing record.");
else {
uint64_t *id_buf = newdup(uint64_t, &tr->id, 1);
if (!id_buf)
log_oom_warning();
else
(void) set_ensure_consume(&j->manager->transactions_with_cycle, &uint64_hash_ops_value_free, id_buf);
}
if (delete) {
const char *status;
/* logging for j not k here to provide a consistent narrative */
@ -1235,20 +1248,24 @@ int transaction_add_triggering_jobs(Transaction *tr, Unit *u) {
return 0;
}
Transaction* transaction_new(bool irreversible) {
Transaction *tr;
Transaction* transaction_new(bool irreversible, uint64_t id) {
_cleanup_free_ Transaction *tr = NULL;
tr = new0(Transaction, 1);
assert(id != 0);
tr = new(Transaction, 1);
if (!tr)
return NULL;
tr->jobs = hashmap_new(NULL);
*tr = (Transaction) {
.jobs = hashmap_new(NULL),
.irreversible = irreversible,
.id = id,
};
if (!tr->jobs)
return mfree(tr);
return NULL;
tr->irreversible = irreversible;
return tr;
return TAKE_PTR(tr);
}
Transaction* transaction_free(Transaction *tr) {

View File

@ -8,9 +8,11 @@ typedef struct Transaction {
Hashmap *jobs; /* Unit object => Job object list 1:1 */
Job *anchor_job; /* The job the user asked for */
bool irreversible;
uint64_t id;
} Transaction;
Transaction* transaction_new(bool irreversible);
Transaction* transaction_new(bool irreversible, uint64_t id);
Transaction* transaction_free(Transaction *tr);
Transaction* transaction_abort_and_free(Transaction *tr);
DEFINE_TRIVIAL_CLEANUP_FUNC(Transaction*, transaction_abort_and_free);

View File

@ -112,6 +112,24 @@ static int manager_context_build_json(sd_json_variant **ret, const char *name, v
JSON_BUILD_PAIR_STRING_NON_EMPTY("ControlGroup", m->cgroup_root));
}
static int transactions_with_cycle_build_json(sd_json_variant **ret, const char *name, void *userdata) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
const Set *ids = userdata;
int r;
assert(ret);
uint64_t *id;
SET_FOREACH(id, ids) {
r = sd_json_variant_append_arrayb(&v, SD_JSON_BUILD_UNSIGNED(*id));
if (r < 0)
return r;
}
*ret = TAKE_PTR(v);
return 0;
}
static int manager_runtime_build_json(sd_json_variant **ret, const char *name, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
dual_timestamp watchdog_last_ping;
@ -154,6 +172,7 @@ static int manager_runtime_build_json(sd_json_variant **ret, const char *name, v
SD_JSON_BUILD_PAIR_UNSIGNED("NJobs", hashmap_size(m->jobs)),
SD_JSON_BUILD_PAIR_UNSIGNED("NInstalledJobs", m->n_installed_jobs),
SD_JSON_BUILD_PAIR_UNSIGNED("NFailedJobs", m->n_failed_jobs),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("TransactionsWithOrderingCycle", transactions_with_cycle_build_json, m->transactions_with_cycle),
SD_JSON_BUILD_PAIR_REAL("Progress", manager_get_progress(m)),
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("WatchdogLastPingTimestamp", watchdog_get_last_ping_as_dual_timestamp(&watchdog_last_ping)),
SD_JSON_BUILD_PAIR_STRING("SystemState", manager_state_to_string(manager_state(m))),

View File

@ -127,7 +127,7 @@ static int add_cryptsetup(
* assignment, under the assumption that people who are fine to use sd-stub with its PCR
* assignments are also OK with our PCR 15 use here. */
if (r > 0)
if (!strextend_with_separator(&options, ",", "tpm2-measure-pcr=yes,tpm2-measure-slot-nvpcr=cryptsetup"))
if (!strextend_with_separator(&options, ",", "tpm2-measure-pcr=yes,tpm2-measure-keyslot-nvpcr=cryptsetup"))
return log_oom();
if (r == 0)
log_debug("Will not measure volume key of volume '%s', not booted via systemd-stub with measurements enabled.", id);

View File

@ -570,7 +570,7 @@ static int home_parse_worker_stdout(int _fd, UserRecord **ret) {
return 0;
}
if (lseek(fd, SEEK_SET, 0) < 0)
if (lseek(fd, 0, SEEK_SET) < 0)
return log_error_errno(errno, "Failed to seek to beginning of memfd: %m");
f = take_fdopen(&fd, "r");

View File

@ -365,7 +365,7 @@ static int raw_pull_make_local_copy(RawPull *i) {
assert(i->raw_job->disk_fd >= 0);
assert(i->offset == UINT64_MAX);
if (lseek(i->raw_job->disk_fd, SEEK_SET, 0) < 0)
if (lseek(i->raw_job->disk_fd, 0, SEEK_SET) < 0)
return log_error_errno(errno, "Failed to seek to beginning of vendor image: %m");
}

View File

@ -186,12 +186,8 @@ int sd_lldp_tx_set_hostname(sd_lldp_tx *lldp_tx, const char *hostname) {
assert_return(lldp_tx, -EINVAL);
/* An empty string unset the previously set hostname. */
if (!isempty(hostname)) {
assert_cc(HOST_NAME_MAX < 512);
if (!hostname_is_valid(hostname, 0))
if (!isempty(hostname) && !hostname_is_valid(hostname, /* flags= */ 0))
return -EINVAL;
}
return free_and_strdup(&lldp_tx->hostname, empty_to_null(hostname));
}

View File

@ -1623,14 +1623,20 @@ int bus_set_address_machine(sd_bus *b, RuntimeScope runtime_scope, const char *m
if (!a)
return -ENOMEM;
bool local = !eh || streq(eh, ".host");
/* Ideally we'd always use the "--user" and "--quiet" switches to systemd-stdio-bridge here,
* but they're only available in recent systemd versions, meaning we can only use them if
* we're not connecting to a container. Using the "-p" switch with an explicit path is a
* working alternative for "--user", and is compatible with older versions, hence that's what
* we use when connecting to a container. */
if (runtime_scope == RUNTIME_SCOPE_USER) {
/* Ideally we'd use the "--user" switch to systemd-stdio-bridge here, but it's only
* available in recent systemd versions. Using the "-p" switch with the explicit path
* is a working alternative, and is compatible with older versions, hence that's what
* we use here. */
if (!strextend(&a, ",argv7=-punix:path%3d%24%7bXDG_RUNTIME_DIR%7d/bus"))
if (!strextend(&a, local ? ",argv7=--user,argv8=--quiet" : ",argv7=-punix:path%3d%24%7bXDG_RUNTIME_DIR%7d/bus"))
return -ENOMEM;
} else if (local)
if (!strextend(&a, ",argv7=--quiet"))
return -ENOMEM;
}
} else {
_cleanup_free_ char *e = NULL;

View File

@ -570,8 +570,8 @@ int seat_read_active_vt(Seat *s) {
if (!seat_has_vts(s))
return 0;
if (lseek(s->manager->console_active_fd, SEEK_SET, 0) < 0)
return log_error_errno(errno, "lseek on console_active_fd failed: %m");
if (lseek(s->manager->console_active_fd, 0, SEEK_SET) < 0)
return log_error_errno(errno, "lseek() on console_active_fd failed: %m");
errno = 0;
k = read(s->manager->console_active_fd, t, sizeof(t)-1);

View File

@ -161,7 +161,11 @@ static int bus_job_get_service_result(BusWaitForJobs *d, char **ret) {
ret);
}
static void log_job_error_with_service_result(const char* service, const char *result, const char* const* extra_args) {
static void log_job_error_with_service_result(
const char* service,
const char *result,
bool quiet,
const char* const* extra_args) {
static const struct {
const char *result, *explanation;
@ -195,7 +199,8 @@ static void log_job_error_with_service_result(const char* service, const char *r
if (!isempty(result))
FOREACH_ELEMENT(i, explanations)
if (streq(result, i->result)) {
log_error("Job for %s failed because %s.\n"
log_full(quiet ? LOG_DEBUG : LOG_ERR,
"Job for %s failed because %s.\n"
"See \"%s status %s\" and \"%s -xeu %s\" for details.\n",
service, i->explanation,
systemctl, service_shell_quoted ?: "<service>",
@ -203,7 +208,8 @@ static void log_job_error_with_service_result(const char* service, const char *r
goto extra;
}
log_error("Job for %s failed.\n"
log_full(quiet ? LOG_DEBUG : LOG_ERR,
"Job for %s failed.\n"
"See \"%s status %s\" and \"%s -xeu %s\" for details.\n",
service,
systemctl, service_shell_quoted ?: "<service>",
@ -212,7 +218,8 @@ static void log_job_error_with_service_result(const char* service, const char *r
extra:
/* For some results maybe additional explanation is required */
if (streq_ptr(result, "start-limit-hit"))
log_info("To force a start use \"%1$s reset-failed %2$s\"\n"
log_full(quiet ? LOG_DEBUG : LOG_INFO,
"To force a start use \"%1$s reset-failed %2$s\"\n"
"followed by \"%1$s start %2$s\" again.",
systemctl,
service_shell_quoted ?: "<service>");
@ -226,38 +233,39 @@ static int check_wait_response(BusWaitForJobs *d, WaitJobsFlags flags, const cha
assert(d->result);
if (streq(d->result, "done")) {
if (FLAGS_SET(flags, BUS_WAIT_JOBS_LOG_SUCCESS))
log_info("Job for %s finished.", d->name);
log_full(FLAGS_SET(flags, BUS_WAIT_JOBS_LOG_SUCCESS) ? LOG_INFO : LOG_DEBUG,
"Job for %s finished.", d->name);
return 0;
} else if (streq(d->result, "skipped")) {
if (FLAGS_SET(flags, BUS_WAIT_JOBS_LOG_SUCCESS))
log_info("Job for %s was skipped.", d->name);
log_full(FLAGS_SET(flags, BUS_WAIT_JOBS_LOG_SUCCESS) ? LOG_INFO : LOG_DEBUG,
"Job for %s was skipped.", d->name);
return 0;
}
if (FLAGS_SET(flags, BUS_WAIT_JOBS_LOG_ERROR)) {
int priority = FLAGS_SET(flags, BUS_WAIT_JOBS_LOG_ERROR) ? LOG_ERR : LOG_DEBUG;
if (streq(d->result, "canceled"))
log_error("Job for %s canceled.", d->name);
log_full(priority, "Job for %s canceled.", d->name);
else if (streq(d->result, "timeout"))
log_error("Job for %s timed out.", d->name);
log_full(priority, "Job for %s timed out.", d->name);
else if (streq(d->result, "dependency"))
log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", d->name);
log_full(priority, "A dependency job for %s failed. See 'journalctl -xe' for details.", d->name);
else if (streq(d->result, "invalid"))
log_error("%s is not active, cannot reload.", d->name);
log_full(priority, "%s is not active, cannot reload.", d->name);
else if (streq(d->result, "assert"))
log_error("Assertion failed on job for %s.", d->name);
log_full(priority, "Assertion failed on job for %s.", d->name);
else if (streq(d->result, "unsupported"))
log_error("Operation on or unit type of %s not supported on this system.", d->name);
log_full(priority, "Operation on or unit type of %s not supported on this system.", d->name);
else if (streq(d->result, "collected"))
log_error("Queued job for %s was garbage collected.", d->name);
log_full(priority, "Queued job for %s was garbage collected.", d->name);
else if (streq(d->result, "once"))
log_error("Unit %s was started already once and can't be started again.", d->name);
log_full(priority, "Unit %s was started already once and can't be started again.", d->name);
else if (streq(d->result, "frozen"))
log_error("Cannot perform operation on frozen unit %s.", d->name);
log_full(priority, "Cannot perform operation on frozen unit %s.", d->name);
else if (streq(d->result, "concurrency"))
log_error("Concurrency limit of a slice unit %s is contained in has been reached.", d->name);
log_full(priority, "Concurrency limit of a slice unit %s is contained in has been reached.", d->name);
else if (endswith(d->name, ".service")) {
/* Job result is unknown. For services, let's also try Result property. */
_cleanup_free_ char *result = NULL;
@ -267,10 +275,9 @@ static int check_wait_response(BusWaitForJobs *d, WaitJobsFlags flags, const cha
log_debug_errno(r, "Failed to get Result property of unit %s, ignoring: %m",
d->name);
log_job_error_with_service_result(d->name, result, extra_args);
log_job_error_with_service_result(d->name, result, priority, extra_args);
} else /* Otherwise we just show a generic message. */
log_error("Job failed. See \"journalctl -xe\" for details.");
}
log_full(priority, "Job failed. See \"journalctl -xe\" for details.");
if (STR_IN_SET(d->result, "canceled", "collected"))
return -ECANCELED;

View File

@ -96,9 +96,11 @@ char* cpu_set_to_mask_string(const CPUSet *c) {
for (size_t i = c->allocated * 8; i > 0; ) {
uint32_t m = 0;
for (int j = (i % 32 ?: 32) - 1; j >= 0; j--)
if (CPU_ISSET_S(--i, c->allocated, c->set))
for (int j = (i % 32 ?: 32) - 1; j >= 0; j--) {
--i;
if (CPU_ISSET_S(i, c->allocated, c->set))
SET_BIT(m, j);
}
if (!found_nonzero) {
if (m == 0)

View File

@ -51,7 +51,7 @@ int sethostname_idempotent(const char *s) {
int shorten_overlong(const char *s, char **ret) {
_cleanup_free_ char *h = NULL;
/* Shorten an overlong name to HOST_NAME_MAX or to the first dot,
/* Shorten an overlong name to LINUX_HOST_NAME_MAX or to the first dot,
* whatever comes earlier. */
assert(s);
@ -70,7 +70,7 @@ int shorten_overlong(const char *s, char **ret) {
if (p)
*p = 0;
strshorten(h, HOST_NAME_MAX);
strshorten(h, LINUX_HOST_NAME_MAX);
if (!hostname_is_valid(h, /* flags= */ 0))
return -EDOM;
@ -403,7 +403,7 @@ int pidref_gethostname_full(PidRef *pidref, GetHostnameFlags flags, char **ret)
if (r < 0)
return r;
char buf[HOST_NAME_MAX+1];
char buf[LINUX_HOST_NAME_MAX+1];
ssize_t n = loop_read(result_pipe[0], buf, sizeof(buf), /* do_poll = */ false);
if (n < 0)
return n;

View File

@ -64,6 +64,7 @@ typedef struct Fido2HmacSalt Fido2HmacSalt;
typedef struct GroupRecord GroupRecord;
typedef struct Image Image;
typedef struct ImagePolicy ImagePolicy;
typedef struct InstallChange InstallChange;
typedef struct InstallInfo InstallInfo;
typedef struct LookupPaths LookupPaths;
typedef struct LoopDevice LoopDevice;

View File

@ -155,6 +155,8 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_DEFINE_FIELD(NInstalledJobs, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("The total amount of failed jobs"),
SD_VARLINK_DEFINE_FIELD(NFailedJobs, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("IDs of transactions that encountered ordering cycle"),
SD_VARLINK_DEFINE_FIELD(TransactionsWithOrderingCycle, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Boot progress as a floating point value between 0.0 and 1.0"),
SD_VARLINK_DEFINE_FIELD(Progress, SD_VARLINK_FLOAT, 0),
SD_VARLINK_FIELD_COMMENT("Timestamp when the hardware watchdog was last pinged"),

View File

@ -17,9 +17,10 @@
#include "parse-argument.h"
#include "time-util.h"
static const char *arg_bus_path = DEFAULT_SYSTEM_BUS_ADDRESS;
static const char *arg_bus_path = NULL;
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
static RuntimeScope arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
static bool arg_quiet = false;
static int help(void) {
printf("%s [OPTIONS...]\n\n"
@ -29,7 +30,8 @@ static int help(void) {
" -p --bus-path=PATH Path to the bus address (default: %s)\n"
" --system Connect to system bus\n"
" --user Connect to user bus\n"
" -M --machine=CONTAINER Name of local container to connect to\n",
" -M --machine=CONTAINER Name of local container to connect to\n"
" -q --quiet Fail silently instead of logging errors\n",
program_invocation_short_name, DEFAULT_SYSTEM_BUS_ADDRESS);
return 0;
@ -50,10 +52,11 @@ static int parse_argv(int argc, char *argv[]) {
{ "user", no_argument, NULL, ARG_USER },
{ "system", no_argument, NULL, ARG_SYSTEM },
{ "machine", required_argument, NULL, 'M' },
{ "quiet", no_argument, NULL, 'q' },
{},
};
int r, c;
int c, r;
assert(argc >= 0);
assert(argv);
@ -86,6 +89,10 @@ static int parse_argv(int argc, char *argv[]) {
return r;
break;
case 'q':
arg_quiet = true;
break;
case '?':
return -EINVAL;
@ -94,18 +101,57 @@ static int parse_argv(int argc, char *argv[]) {
}
if (argc > optind)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
return log_full_errno(arg_quiet ? LOG_DEBUG : LOG_ERR, SYNTHETIC_ERRNO(EINVAL),
"%s takes no arguments.",
program_invocation_short_name);
return 1;
}
static int bus_set_address(
sd_bus *bus,
BusTransport transport,
const char *bus_path,
RuntimeScope runtime_scope) {
int r;
assert(bus);
switch (transport) {
case BUS_TRANSPORT_LOCAL:
if (bus_path)
return sd_bus_set_address(bus, bus_path);
switch (runtime_scope) {
case RUNTIME_SCOPE_USER:
return bus_set_address_user(bus);
case RUNTIME_SCOPE_SYSTEM:
return bus_set_address_system(bus);
default:
assert_not_reached();
}
case BUS_TRANSPORT_MACHINE:
return bus_set_address_machine(bus, runtime_scope, bus_path);
default:
assert_not_reached();
}
return r;
}
static int run(int argc, char *argv[]) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *a = NULL, *b = NULL;
sd_id128_t server_id;
bool is_unix;
int r, in_fd, out_fd;
int in_fd, out_fd, r;
log_setup();
@ -113,6 +159,8 @@ static int run(int argc, char *argv[]) {
if (r <= 0)
return r;
int priority = arg_quiet ? LOG_DEBUG : LOG_ERR;
r = sd_listen_fds(0);
if (r == 0) {
in_fd = STDIN_FILENO;
@ -121,7 +169,8 @@ static int run(int argc, char *argv[]) {
in_fd = SD_LISTEN_FDS_START;
out_fd = SD_LISTEN_FDS_START;
} else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "More than one file descriptor was passed.");
return log_full_errno(priority, SYNTHETIC_ERRNO(EINVAL),
"More than one file descriptor was passed.");
is_unix =
sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
@ -129,50 +178,47 @@ static int run(int argc, char *argv[]) {
r = sd_bus_new(&a);
if (r < 0)
return log_error_errno(r, "Failed to allocate bus: %m");
return log_full_errno(priority, r, "Failed to allocate bus: %m");
if (arg_transport == BUS_TRANSPORT_MACHINE)
r = bus_set_address_machine(a, arg_runtime_scope, arg_bus_path);
else
r = sd_bus_set_address(a, arg_bus_path);
r = bus_set_address(a, arg_transport, arg_bus_path, arg_runtime_scope);
if (r < 0)
return log_error_errno(r, "Failed to set address to connect to: %m");
return log_full_errno(priority, r, "Failed to set address to connect to: %m");
r = sd_bus_negotiate_fds(a, is_unix);
if (r < 0)
return log_error_errno(r, "Failed to set FD negotiation: %m");
return log_full_errno(priority, r, "Failed to set FD negotiation: %m");
r = sd_bus_start(a);
if (r < 0)
return bus_log_connect_error(r, arg_transport, arg_runtime_scope);
return bus_log_connect_full(priority, r, arg_transport, arg_runtime_scope);
r = sd_bus_get_bus_id(a, &server_id);
if (r < 0)
return log_error_errno(r, "Failed to get server ID: %m");
return log_full_errno(priority, r, "Failed to get server ID: %m");
r = sd_bus_new(&b);
if (r < 0)
return log_error_errno(r, "Failed to allocate bus: %m");
return log_full_errno(priority, r, "Failed to allocate bus: %m");
r = sd_bus_set_fd(b, in_fd, out_fd);
if (r < 0)
return log_error_errno(r, "Failed to set fds: %m");
return log_full_errno(priority, r, "Failed to set fds: %m");
r = sd_bus_set_server(b, 1, server_id);
if (r < 0)
return log_error_errno(r, "Failed to set server mode: %m");
return log_full_errno(priority, r, "Failed to set server mode: %m");
r = sd_bus_negotiate_fds(b, is_unix);
if (r < 0)
return log_error_errno(r, "Failed to set FD negotiation: %m");
return log_full_errno(priority, r, "Failed to set FD negotiation: %m");
r = sd_bus_set_anonymous(b, true);
if (r < 0)
return log_error_errno(r, "Failed to set anonymous authentication: %m");
return log_full_errno(priority, r, "Failed to set anonymous authentication: %m");
r = sd_bus_start(b);
if (r < 0)
return log_error_errno(r, "Failed to start bus forwarding server: %m");
return log_full_errno(priority, r, "Failed to start bus forwarding server: %m");
for (;;) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
@ -185,14 +231,14 @@ static int run(int argc, char *argv[]) {
if (ERRNO_IS_NEG_DISCONNECT(r)) /* Treat 'connection reset by peer' as clean exit condition */
return 0;
if (r < 0)
return log_error_errno(r, "Failed to process bus a: %m");
return log_full_errno(priority, r, "Failed to process bus a: %m");
if (m) {
if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
return 0;
r = sd_bus_send(b, m, NULL);
if (r < 0)
return log_error_errno(r, "Failed to send message: %m");
return log_full_errno(priority, r, "Failed to send message: %m");
}
if (r > 0)
@ -202,14 +248,14 @@ static int run(int argc, char *argv[]) {
if (ERRNO_IS_NEG_DISCONNECT(r)) /* Treat 'connection reset by peer' as clean exit condition */
return 0;
if (r < 0)
return log_error_errno(r, "Failed to process bus: %m");
return log_full_errno(priority, r, "Failed to process bus: %m");
if (m) {
if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
return 0;
r = sd_bus_send(a, m, NULL);
if (r < 0)
return log_error_errno(r, "Failed to send message: %m");
return log_full_errno(priority, r, "Failed to send message: %m");
}
if (r > 0)
@ -217,23 +263,23 @@ static int run(int argc, char *argv[]) {
fd = sd_bus_get_fd(a);
if (fd < 0)
return log_error_errno(fd, "Failed to get fd: %m");
return log_full_errno(priority, fd, "Failed to get fd: %m");
events_a = sd_bus_get_events(a);
if (events_a < 0)
return log_error_errno(events_a, "Failed to get events mask: %m");
return log_full_errno(priority, events_a, "Failed to get events mask: %m");
r = sd_bus_get_timeout(a, &timeout_a);
if (r < 0)
return log_error_errno(r, "Failed to get timeout: %m");
return log_full_errno(priority, r, "Failed to get timeout: %m");
events_b = sd_bus_get_events(b);
if (events_b < 0)
return log_error_errno(events_b, "Failed to get events mask: %m");
return log_full_errno(priority, events_b, "Failed to get events mask: %m");
r = sd_bus_get_timeout(b, &timeout_b);
if (r < 0)
return log_error_errno(r, "Failed to get timeout: %m");
return log_full_errno(priority, r, "Failed to get timeout: %m");
t = usec_sub_unsigned(MIN(timeout_a, timeout_b), now(CLOCK_MONOTONIC));
@ -245,7 +291,7 @@ static int run(int argc, char *argv[]) {
r = ppoll_usec(p, ELEMENTSOF(p), t);
if (r < 0 && !ERRNO_IS_TRANSIENT(r)) /* don't be bothered by signals, i.e. EINTR */
return log_error_errno(r, "ppoll() failed: %m");
return log_full_errno(priority, r, "ppoll() failed: %m");
}
}

View File

@ -17,6 +17,7 @@ test_env = {
'SYSTEMD_DEFAULT_LOCALE' : get_option('default-locale'),
'SYSTEMD_SLOW_TESTS' : want_slow_tests ? '1' : '0',
'PYTHONDONTWRITEBYTECODE' : '1',
'SYSTEMD_LIBC' : get_option('libc'),
}
if conf.get('ENABLE_LOCALED') == 1
test_env += {'SYSTEMD_LANGUAGE_FALLBACK_MAP' : language_fallback_map}

View File

@ -124,7 +124,7 @@ TEST(copy_file_fd) {
assert_se(write_string_file(in_fn, text, WRITE_STRING_FILE_CREATE) == 0);
assert_se(copy_file_fd("/a/file/which/does/not/exist/i/guess", out_fd, COPY_REFLINK) < 0);
assert_se(copy_file_fd(in_fn, out_fd, COPY_REFLINK) >= 0);
assert_se(lseek(out_fd, SEEK_SET, 0) == 0);
assert_se(lseek(out_fd, 0, SEEK_SET) == 0);
assert_se(read(out_fd, buf, sizeof buf) == (ssize_t) strlen(text));
ASSERT_STREQ(buf, text);

View File

@ -127,7 +127,7 @@ TEST(os_release_support_ended) {
ASSERT_TRUE(os_release_support_ended("1999-01-01", false, NULL));
ASSERT_FALSE(os_release_support_ended("2037-12-31", false, NULL));
assert_se(os_release_support_ended("-1-1-1", true, NULL) == -EINVAL);
ASSERT_ERROR(os_release_support_ended("1-1-1", true, NULL), ERANGE);
r = os_release_support_ended(NULL, false, NULL);
if (r < 0)

View File

@ -525,7 +525,7 @@ TEST(pid_get_cmdline_harder) {
#define EXPECT1p "foo $'\\'bar\\'' $'\"bar$\"' $'x y z' $'!``'"
#define EXPECT1v STRV_MAKE("foo", "'bar'", "\"bar$\"", "x y z", "!``")
ASSERT_OK_ZERO_ERRNO(lseek(fd, SEEK_SET, 0));
ASSERT_OK_ZERO_ERRNO(lseek(fd, 0, SEEK_SET));
ASSERT_OK_EQ_ERRNO(write(fd, CMDLINE1, sizeof(CMDLINE1)), (ssize_t) sizeof(CMDLINE1));
ASSERT_OK_ZERO_ERRNO(ftruncate(fd, sizeof(CMDLINE1)));
@ -550,7 +550,7 @@ TEST(pid_get_cmdline_harder) {
#define EXPECT2p "foo $'\\001\\002\\003'"
#define EXPECT2v STRV_MAKE("foo", "\1\2\3")
ASSERT_OK_ZERO_ERRNO(lseek(fd, SEEK_SET, 0));
ASSERT_OK_ZERO_ERRNO(lseek(fd, 0, SEEK_SET));
ASSERT_OK_EQ_ERRNO(write(fd, CMDLINE2, sizeof(CMDLINE2)), (ssize_t) sizeof(CMDLINE2));
ASSERT_OK_ZERO_ERRNO(ftruncate(fd, sizeof CMDLINE2));

View File

@ -559,7 +559,11 @@ TEST(memory_deny_write_execute_mmap) {
p = mmap(NULL, page_size(), PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
#if defined(__x86_64__) || defined(__i386__) || defined(__powerpc64__) || defined(__arm__) || defined(__aarch64__) || defined(__loongarch_lp64)
assert_se(p == MAP_FAILED);
assert_se(errno == EPERM);
# ifdef __GLIBC__
ASSERT_EQ(errno, EPERM);
# else
ASSERT_EQ(errno, ENOMEM); /* musl maps EPERM to ENOMEM. See src/mman/mmap.c in musl. */
# endif
#endif
/* Depending on kernel, libseccomp, and glibc versions, other architectures
* might fail or not. Let's not assert success. */

View File

@ -13,8 +13,9 @@ TEST(rt_signals) {
info(SIGRTMIN);
info(SIGRTMAX);
/* We use signals SIGRTMIN+0 to SIGRTMIN+30 unconditionally */
assert_se(SIGRTMAX - SIGRTMIN >= 30);
/* We use signals SIGRTMIN+0 to SIGRTMIN+29 unconditionally. SIGRTMIN+30 can be used only when
* built with glibc. */
assert_se(SIGRTMAX - SIGRTMIN >= 29);
}
static void test_signal_to_string_one(int val) {

View File

@ -69,7 +69,7 @@ int probe_smart_media(int mtd_fd, mtd_info_t* info) {
}
for (offset = 0; offset < block_size * spare_count; offset += sector_size) {
(void) lseek(mtd_fd, SEEK_SET, offset);
(void) lseek(mtd_fd, offset, SEEK_SET);
if (read(mtd_fd, cis_buffer, SM_SECTOR_SIZE) == SM_SECTOR_SIZE) {
cis_found = 1;

View File

@ -13,6 +13,7 @@ if conf.get('ENABLE_SYSUSERS') == 1
# https://github.com/mesonbuild/meson/issues/2681
args : exe.full_path(),
depends : exe,
env : test_env,
suite : 'sysusers')
if have_standalone_binaries
@ -22,6 +23,7 @@ if conf.get('ENABLE_SYSUSERS') == 1
# https://github.com/mesonbuild/meson/issues/2681
args : exe.full_path(),
depends : exe,
env : test_env,
suite : 'sysusers')
endif
endif

View File

@ -13,6 +13,12 @@ TESTDIR=$(mktemp --tmpdir --directory "test-sysusers.XXXXXXXXXX")
# shellcheck disable=SC2064
trap "rm -rf '$TESTDIR'" EXIT INT QUIT PIPE
skip_nis() {
# musl seems to not support NIS entries. Let's skip the test case for NIS entries.
local path=${1:?}
[[ "${SYSTEMD_LIBC:-}" == musl && "${path##*/}" == "test-11.input" ]]
}
prepare_testdir() {
mkdir -p "$TESTDIR/etc/sysusers.d/"
mkdir -p "$TESTDIR/usr/lib/sysusers.d/"
@ -50,6 +56,7 @@ rm -f "$TESTDIR"/etc/sysusers.d/* "$TESTDIR"/usr/lib/sysusers.d/*
# happy tests
for f in $(find "$SOURCE"/test-*.input | sort -V); do
skip_nis "$f" && continue
echo "*** Running $f"
prepare_testdir "${f%.input}"
cp "$f" "$TESTDIR/usr/lib/sysusers.d/test.conf"
@ -59,6 +66,7 @@ for f in $(find "$SOURCE"/test-*.input | sort -V); do
done
for f in $(find "$SOURCE"/test-*.input | sort -V); do
skip_nis "$f" && continue
echo "*** Running $f on stdin"
prepare_testdir "${f%.input}"
touch "$TESTDIR/etc/sysusers.d/test.conf"
@ -68,6 +76,7 @@ for f in $(find "$SOURCE"/test-*.input | sort -V); do
done
for f in $(find "$SOURCE"/test-*.input | sort -V); do
skip_nis "$f" && continue
echo "*** Running $f on stdin with --replace"
prepare_testdir "${f%.input}"
touch "$TESTDIR/etc/sysusers.d/test.conf"
@ -133,6 +142,7 @@ SYS_GID_MAX999
EOF
for f in $(find "$SOURCE"/test-*.input | sort -V); do
skip_nis "$f" && continue
echo "*** Running $f (with login.defs)"
prepare_testdir "${f%.input}"
cp "$f" "$TESTDIR/usr/lib/sysusers.d/test.conf"
@ -149,6 +159,7 @@ mv "$TESTDIR/etc/login.defs" "$TESTDIR/etc/login.defs.moved"
ln -s ../../../../../etc/login.defs.moved "$TESTDIR/etc/login.defs"
for f in $(find "$SOURCE"/test-*.input | sort -V); do
skip_nis "$f" && continue
echo "*** Running $f (with login.defs symlinked)"
prepare_testdir "${f%.input}"
cp "$f" "$TESTDIR/usr/lib/sysusers.d/test.conf"
@ -161,13 +172,22 @@ done
rm -f "$TESTDIR"/etc/sysusers.d/* "$TESTDIR"/usr/lib/sysusers.d/*
preprocess_error() {
# Convert error message for ERANGE from glibc to musl.
if [[ "${SYSTEMD_LIBC:-}" == musl ]]; then
sed -e 's/Numerical result out of range/Result not representable/' "${1:?}"
else
cat "${1:?}"
fi
}
# tests for error conditions
for f in $(find "$SOURCE"/unhappy-*.input | sort -V); do
echo "*** Running test $f"
prepare_testdir "${f%.input}"
cp "$f" "$TESTDIR/usr/lib/sysusers.d/test.conf"
SYSTEMD_LOG_LEVEL=info "$SYSUSERS" --root="$TESTDIR" 2>&1 | tail -n1 | sed -r 's/^[^:]+:[^:]+://' >"$TESTDIR/err"
if ! diff -u "$TESTDIR/err" "${f%.*}.expected-err" >&2; then
if ! diff -u "$TESTDIR/err" <(preprocess_error "${f%.*}.expected-err") >&2; then
echo >&2 "**** Unexpected error output for $f"
cat >&2 "$TESTDIR/err"
exit 1

View File

@ -124,6 +124,13 @@ for i in {0..19}; do
systemctl start "transaction-cycle$i.service"
done
IDS_FILE="/tmp/TEST-03-JOBS-CYCLE-IDS-$RANDOM"
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Manager.Describe '{}' | jq '.runtime.TransactionsWithOrderingCycle' >"$IDS_FILE"
[[ "$(jq length "$IDS_FILE")" -ge 20 ]]
for i in {0..19}; do
journalctl -b TRANSACTION_ID="$(jq -r ".[$i]" "$IDS_FILE")" --grep "cycle starting with"
done
# Test PropagatesStopTo= when restart (issue #26839)
systemctl start propagatestopto-and-pullin.target
systemctl --quiet is-active propagatestopto-and-pullin.target