1
0
mirror of https://github.com/systemd/systemd.git synced 2024-10-26 08:55:40 +03:00

Compare commits

...

13 Commits

Author SHA1 Message Date
Lennart Poettering
442fd288cb
Merge 45d721d8db into ddb8a639d5 2024-10-25 21:49:18 -07:00
Integral
ddb8a639d5
tree-wide: replace for loop with FOREACH_ELEMENT or FOREACH_ARRAY macros (#34893) 2024-10-26 07:10:22 +09:00
Yu Watanabe
f7078de515
Merge pull request #34884 from poettering/run0-disconnect-fix
run: reconnect if our dbus connection is terminated
2024-10-26 02:50:48 +09:00
Yu Watanabe
6d6048b4cb
Merge pull request #34881 from poettering/run0-ui-tweaks
run0: various UI tweaks
2024-10-26 02:49:48 +09:00
Ivan Kruglov
10a48938ef machine: operation should not send a response when 'done' callback set 2024-10-26 02:45:53 +09:00
Lennart Poettering
b58b13f1c6 test: add brief testcase for systemd-run disconnect handling 2024-10-25 17:51:04 +02:00
Lennart Poettering
c8f59296bf run: reconnect if our dbus connection is terminated
We must be prepared that systemd temporarily drops off the bus or
disconnects our direct connections (due to systemctl daemon-reexec or
so). Hence automatically reconnect when we watch the unit status, and
handle this case gracefully.

Fixes: #32906 #27204
2024-10-25 17:51:04 +02:00
Lennart Poettering
d585085f57 update TODO 2024-10-25 17:32:19 +02:00
Lennart Poettering
ff4b6a1915 run: drop "-" prefix from command line when generating unit description
Let's not confuse users with the login shell indicator and drop it from
the description. This means a run0 session will now usually show up with
a description of "[run0] /bin/bash" rather than "[run0] -/bin/bash".
2024-10-25 17:32:19 +02:00
Lennart Poettering
d9f68f48f7 run: prefix unit description with our own process name
I think we should try to communicate clearly if something is a run0
session, or a systemd-run invocation. Hence, let's initialize the
description so that the command is prefixed by
program_invocation_short_name.

Effectively this means that our run0 sessions now appear as services
with a description of "[run0] -/bin/bash"
2024-10-25 17:32:19 +02:00
Lennart Poettering
0310b2a60b run: tweak how we name our transient units
The current logic is a bit complex how systemd-run units are called. It
used to be just the unique ID of the dbus connection. Which was nice,
since its system-widely, uniquely assigned to us. But this didn't work
out well, due to direct connections to PID 1 and due to soft reboots.

We nowadays have a better ID to use though, with nicer properties: the
kernel manages a pidfd ID for every process after all, and it's globally
unique, for any process, and regardless of soft reboots. Hence use that
for naming preferably, and just keep one branch with a randomized name
as fallback.
2024-10-25 17:32:19 +02:00
Lennart Poettering
115fac3c29 run0: optionally show superhero emoji on each shell prompt
This makes use of the infra introduced in 229d4a9806 to indicate visually on each prompt that we are in superuser mode temporarily.
pick ad5de3222f userdbctl: add some basic client-side filtering
2024-10-25 17:31:06 +02:00
Lennart Poettering
45d721d8db doc: don't talk of "trailing NUL bytes" in UTF-16 context, but rather "trailing U+0000 codepoints"
Addresses:

https://mastodon.social/@grawity@treehouse.systems/111220532872832265
2023-10-12 12:11:19 +02:00
55 changed files with 591 additions and 416 deletions

3
TODO
View File

@ -162,9 +162,6 @@ Features:
sd_event_add_child(), and then get rid of many more explicit sigprocmask()
calls.
* maybe set shell.prompt.prefix credential in run0 to some warning emoji,
i.e. ⚠️ or ☢️ or ⚡ or 👊 or 🧑‍🔧 or so.
* introduce new structure Tpm2CombinedPolicy, that combines the various TPm2
policy bits into one structure, i.e. public key info, pcr masks, pcrlock
stuff, pin and so on. Then pass that around in tpm2_seal() and tpm2_unseal().

View File

@ -41,7 +41,7 @@ used for new, additional measurements.
## PCR Measurements Made by `systemd-boot` (UEFI)
### PCS 5, `EV_EVENT_TAG`, "loader.conf"
### PCR 5, `EV_EVENT_TAG`, "loader.conf"
The content of `systemd-boot`'s configuration file, `loader/loader.conf`, is
measured as a tagged event.
@ -66,7 +66,7 @@ below for details on PE section measurements done by `systemd-stub`.)
UTF-16.
**Measured hash** covers the literal kernel command line in UTF-16 (without any
trailing NUL bytes).
trailing U+0000 codepoints).
## PCR Measurements Made by `systemd-stub` (UEFI)
@ -108,7 +108,7 @@ Might happen up to three times, for kernel command lines from:
UTF-16.
**Measured hash** covers the literal kernel command line in UTF-16 (without any
trailing NUL bytes).
trailing U+0000 codepoints).
### PCR 12, `EV_EVENT_TAG`, "Devicetrees"

View File

@ -207,6 +207,20 @@
</listitem>
</varlistentry>
<varlistentry>
<term><option>--shell-prompt-prefix=<replaceable>STRING</replaceable></option></term>
<listitem><para>Set a shell prompt prefix string. This ultimately controls the
<varname>$SHELL_PROMPT_PREFIX</varname> environment variable for the invoked program, which is
typically imported into the shell prompt. By default if emojis are supported a superhero emoji is
shown (🦸). This default may also be changed (or turned off) by passing the
<varname>$SYSTEMD_RUN_SHELL_PROMPT_PREFIX</varname> environment variable to <varname>run0</varname>,
see below. Set to an empty string to disable shell prompt prefixing.</para>
<xi:include href="version-info.xml" xpointer="v257"/>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--machine=</option></term>
@ -271,7 +285,30 @@
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>$SHELL_PROMPT_PREFIX</varname></term>
<listitem><para>By default set to the superhero emoji (if supported), but may be overriden with the
<varname>$SYSTEMD_RUN_SHELL_PROMPT_PREFIX</varname> environment variable (see below), or the
<option>--shell-prompt-prefix=</option> switch (see above).</para>
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
</varlistentry>
</variablelist>
<para>The following variables may be passed to <command>run0</command>:</para>
<variablelist>
<varlistentry>
<term><varname>$SYSTEMD_RUN_SHELL_PROMPT_PREFIX</varname></term>
<listitem><para>If set, overrides the default shell prompt prefix that <command>run0</command> sets
for the invoked shell (the superhero emoji). Set to an empty string to disable shell prompt
prefixing.</para>
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>

View File

@ -130,9 +130,9 @@ Architecture uname_architecture(void) {
assert_se(uname(&u) >= 0);
for (size_t i = 0; i < ELEMENTSOF(arch_map); i++)
if (streq(arch_map[i].machine, u.machine))
return cached = arch_map[i].arch;
FOREACH_ELEMENT(entry, arch_map)
if (streq(entry->machine, u.machine))
return cached = entry->arch;
assert_not_reached();
return _ARCHITECTURE_INVALID;

View File

@ -80,6 +80,7 @@ const char* special_glyph_full(SpecialGlyph code, bool force_utf) {
[SPECIAL_GLYPH_YELLOW_CIRCLE] = "o",
[SPECIAL_GLYPH_BLUE_CIRCLE] = "o",
[SPECIAL_GLYPH_GREEN_CIRCLE] = "o",
[SPECIAL_GLYPH_SUPERHERO] = "S",
},
/* UTF-8 */
@ -149,6 +150,7 @@ const char* special_glyph_full(SpecialGlyph code, bool force_utf) {
[SPECIAL_GLYPH_YELLOW_CIRCLE] = u8"🟡",
[SPECIAL_GLYPH_BLUE_CIRCLE] = u8"🔵",
[SPECIAL_GLYPH_GREEN_CIRCLE] = u8"🟢",
[SPECIAL_GLYPH_SUPERHERO] = u8"🦸",
},
};

View File

@ -55,6 +55,7 @@ typedef enum SpecialGlyph {
SPECIAL_GLYPH_YELLOW_CIRCLE,
SPECIAL_GLYPH_BLUE_CIRCLE,
SPECIAL_GLYPH_GREEN_CIRCLE,
SPECIAL_GLYPH_SUPERHERO,
_SPECIAL_GLYPH_MAX,
_SPECIAL_GLYPH_INVALID = -EINVAL,
} SpecialGlyph;

View File

@ -71,13 +71,13 @@ int proc_cmdline_filter_pid1_args(char **argv, char ***ret) {
}
/* long option, e.g. --foo */
for (size_t i = 0; i < ELEMENTSOF(options); i++) {
const char *q = startswith(a + 2, options[i].name);
FOREACH_ELEMENT(option, options) {
const char *q = startswith(a + 2, option->name);
if (!q || !IN_SET(q[0], '=', '\0'))
continue;
/* Found matching option, updating the state if necessary. */
if (q[0] == '\0' && options[i].has_arg == required_argument)
if (q[0] == '\0' && option->has_arg == required_argument)
state = required_argument;
break;

View File

@ -556,7 +556,7 @@ char* format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
/* The result of this function can be parsed with parse_sec */
for (size_t i = 0; i < ELEMENTSOF(table); i++) {
FOREACH_ELEMENT(i, table) {
int k = 0;
size_t n;
bool done = false;
@ -568,20 +568,20 @@ char* format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
if (t < accuracy && something)
break;
if (t < table[i].usec)
if (t < i->usec)
continue;
if (l <= 1)
break;
a = t / table[i].usec;
b = t % table[i].usec;
a = t / i->usec;
b = t % i->usec;
/* Let's see if we should shows this in dot notation */
if (t < USEC_PER_MINUTE && b > 0) {
signed char j = 0;
for (usec_t cc = table[i].usec; cc > 1; cc /= 10)
for (usec_t cc = i->usec; cc > 1; cc /= 10)
j++;
for (usec_t cc = accuracy; cc > 1; cc /= 10) {
@ -596,7 +596,7 @@ char* format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
a,
j,
b,
table[i].suffix);
i->suffix);
t = 0;
done = true;
@ -609,7 +609,7 @@ char* format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
"%s"USEC_FMT"%s",
p > buf ? " " : "",
a,
table[i].suffix);
i->suffix);
t = b;
}
@ -795,12 +795,12 @@ static int parse_timestamp_impl(
goto from_tm;
}
for (size_t i = 0; i < ELEMENTSOF(day_nr); i++) {
k = startswith_no_case(t, day_nr[i].name);
FOREACH_ELEMENT(day, day_nr) {
k = startswith_no_case(t, day->name);
if (!k || *k != ' ')
continue;
weekday = day_nr[i].nr;
weekday = day->nr;
t = k + 1;
break;
}
@ -1122,12 +1122,12 @@ static const char* extract_multiplier(const char *p, usec_t *ret) {
assert(p);
assert(ret);
for (size_t i = 0; i < ELEMENTSOF(table); i++) {
FOREACH_ELEMENT(i, table) {
char *e;
e = startswith(p, table[i].suffix);
e = startswith(p, i->suffix);
if (e) {
*ret = table[i].usec;
*ret = i->usec;
return e;
}
}
@ -1300,17 +1300,16 @@ static const char* extract_nsec_multiplier(const char *p, nsec_t *ret) {
{ "ns", 1ULL },
{ "", 1ULL }, /* default is nsec */
};
size_t i;
assert(p);
assert(ret);
for (i = 0; i < ELEMENTSOF(table); i++) {
FOREACH_ELEMENT(i, table) {
char *e;
e = startswith(p, table[i].suffix);
e = startswith(p, i->suffix);
if (e) {
*ret = table[i].nsec;
*ret = i->nsec;
return e;
}
}

View File

@ -83,10 +83,10 @@ static Virtualization detect_vm_cpuid(void) {
log_debug("Virtualization found, CPUID=%s", sig.text);
for (size_t i = 0; i < ELEMENTSOF(vm_table); i++)
FOREACH_ELEMENT(vm, vm_table)
if (memcmp_nn(sig.text, sizeof(sig.text),
vm_table[i].sig, sizeof(vm_table[i].sig)) == 0)
return vm_table[i].id;
vm->sig, sizeof(vm->sig)) == 0)
return vm->id;
log_debug("Unknown virtualization with CPUID=%s. Add to vm_table[]?", sig.text);
return VIRTUALIZATION_VM_OTHER;
@ -202,10 +202,10 @@ static Virtualization detect_vm_dmi_vendor(void) {
return r;
}
for (size_t i = 0; i < ELEMENTSOF(dmi_vendor_table); i++)
if (startswith(s, dmi_vendor_table[i].vendor)) {
FOREACH_ELEMENT(dmi_vendor, dmi_vendor_table)
if (startswith(s, dmi_vendor->vendor)) {
log_debug("Virtualization %s found in DMI (%s)", s, *vendor);
return dmi_vendor_table[i].id;
return dmi_vendor->id;
}
}
log_debug("No virtualization found in DMI vendor table.");
@ -658,14 +658,14 @@ static Virtualization detect_container_files(void) {
{ "/.dockerenv", VIRTUALIZATION_DOCKER },
};
for (size_t i = 0; i < ELEMENTSOF(container_file_table); i++) {
if (access(container_file_table[i].file_path, F_OK) >= 0)
return container_file_table[i].id;
FOREACH_ELEMENT(file, container_file_table) {
if (access(file->file_path, F_OK) >= 0)
return file->id;
if (errno != ENOENT)
log_debug_errno(errno,
"Checking if %s exists failed, ignoring: %m",
container_file_table[i].file_path);
file->file_path);
}
return VIRTUALIZATION_NONE;

View File

@ -108,8 +108,8 @@ static void validate_sha256(void) {
0xaf, 0xac, 0x45, 0x03, 0x7a, 0xfe, 0xe9, 0xd1 }},
};
for (size_t i = 0; i < ELEMENTSOF(array); i++)
assert(memcmp(SHA256_DIRECT(array[i].string, strlen8(array[i].string)), array[i].hash, HASH_VALUE_SIZE) == 0);
FOREACH_ELEMENT(i, array)
assert(memcmp(SHA256_DIRECT(i->string, strlen8(i->string)), i->hash, HASH_VALUE_SIZE) == 0);
#endif
}

View File

@ -136,14 +136,14 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path, bool
};
/* Make sure all keys files exist before we start enrolling them by loading them from the disk first. */
for (size_t i = 0; i < ELEMENTSOF(sb_vars); i++) {
err = file_read(dir, sb_vars[i].filename, 0, 0, &sb_vars[i].buffer, &sb_vars[i].size);
if (err != EFI_SUCCESS && sb_vars[i].required) {
log_error_status(err, "Failed reading file %ls\\%ls: %m", path, sb_vars[i].filename);
FOREACH_ELEMENT(sb_var, sb_vars) {
err = file_read(dir, sb_var->filename, 0, 0, &sb_var->buffer, &sb_var->size);
if (err != EFI_SUCCESS && sb_var->required) {
log_error_status(err, "Failed reading file %ls\\%ls: %m", path, sb_var->filename);
goto out_deallocate;
}
if (streq16(sb_vars[i].name, u"PK") && sb_vars[i].size > 20) {
assert(sb_vars[i].buffer);
if (streq16(sb_var->name, u"PK") && sb_var->size > 20) {
assert(sb_var->buffer);
/*
* The buffer should be EFI_TIME (16 bytes), followed by
* EFI_VARIABLE_AUTHENTICATION_2 header. First header field is the size. If the
@ -151,7 +151,7 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path, bool
* bytes), leaving no space for an actual signature, we can conclude that no
* signature is present.
*/
uint32_t *sigsize = (uint32_t*)(sb_vars[i].buffer + 16);
uint32_t *sigsize = (uint32_t*)(sb_var->buffer + 16);
if (*sigsize <= 24) {
printf("PK is not signed (need custom mode).\n");
need_custom_mode = true;
@ -168,19 +168,19 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path, bool
printf("Custom mode enabled.\n");
}
for (size_t i = 0; i < ELEMENTSOF(sb_vars); i++) {
FOREACH_ELEMENT(sb_var, sb_vars) {
uint32_t sb_vars_opts =
EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
if (!sb_vars[i].buffer)
if (!sb_var->buffer)
continue;
err = efivar_set_raw(&sb_vars[i].vendor, sb_vars[i].name, sb_vars[i].buffer, sb_vars[i].size, sb_vars_opts);
err = efivar_set_raw(&sb_var->vendor, sb_var->name, sb_var->buffer, sb_var->size, sb_vars_opts);
if (err != EFI_SUCCESS) {
log_error_status(err, "Failed to write %ls secure boot variable: %m", sb_vars[i].name);
log_error_status(err, "Failed to write %ls secure boot variable: %m", sb_var->name);
goto out_deallocate;
}
}
@ -193,8 +193,8 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path, bool
assert_not_reached();
out_deallocate:
for (size_t i = 0; i < ELEMENTSOF(sb_vars); i++)
free(sb_vars[i].buffer);
FOREACH_ELEMENT(sb_var, sb_vars)
free(sb_var->buffer);
return err;
}

View File

@ -176,13 +176,13 @@ static int automount_verify(Automount *a) {
if (!unit_has_name(UNIT(a), e))
return log_unit_error_errno(UNIT(a), SYNTHETIC_ERRNO(ENOEXEC), "Where= setting doesn't match unit name. Refusing.");
for (size_t i = 0; i < ELEMENTSOF(reserved_options); i++)
if (fstab_test_option(a->extra_options, reserved_options[i]))
FOREACH_ELEMENT(reserved_option, reserved_options)
if (fstab_test_option(a->extra_options, *reserved_option))
return log_unit_error_errno(
UNIT(a),
SYNTHETIC_ERRNO(ENOEXEC),
"ExtraOptions= setting may not contain reserved option %s.",
reserved_options[i]);
*reserved_option);
return 0;
}

View File

@ -372,7 +372,6 @@ static int device_found_from_string_many(const char *name, DeviceFound *ret) {
for (;;) {
_cleanup_free_ char *word = NULL;
DeviceFound f = 0;
unsigned i;
r = extract_first_word(&name, &word, ",", 0);
if (r < 0)
@ -380,9 +379,9 @@ static int device_found_from_string_many(const char *name, DeviceFound *ret) {
if (r == 0)
break;
for (i = 0; i < ELEMENTSOF(device_found_map); i++)
if (streq(word, device_found_map[i].name)) {
f = device_found_map[i].flag;
FOREACH_ELEMENT(i, device_found_map)
if (streq(word, i->name)) {
f = i->flag;
break;
}

View File

@ -6383,9 +6383,9 @@ void unit_dump_config_items(FILE *f) {
p->ltype == DISABLED_LEGACY)
continue;
for (size_t j = 0; j < ELEMENTSOF(table); j++)
if (p->parse == table[j].callback) {
rvalue = table[j].rvalue;
FOREACH_ELEMENT(j, table)
if (p->parse == j->callback) {
rvalue = j->rvalue;
break;
}

View File

@ -419,12 +419,11 @@ static void print_unit_dependency_mask(FILE *f, const char *kind, UnitDependency
assert(kind);
assert(space);
for (size_t i = 0; i < ELEMENTSOF(table); i++) {
FOREACH_ELEMENT(i, table) {
if (mask == 0)
break;
if (FLAGS_SET(mask, table[i].mask)) {
if (FLAGS_SET(mask, i->mask)) {
if (*space)
fputc(' ', f);
else
@ -432,9 +431,9 @@ static void print_unit_dependency_mask(FILE *f, const char *kind, UnitDependency
fputs(kind, f);
fputs("-", f);
fputs(table[i].name, f);
fputs(i->name, f);
mask &= ~table[i].mask;
mask &= ~i->mask;
}
}

View File

@ -74,12 +74,12 @@ static const char *translate_runlevel(int runlevel, bool *isolate) {
assert(isolate);
for (size_t i = 0; i < ELEMENTSOF(table); i++)
if (table[i].runlevel == runlevel) {
*isolate = table[i].isolate;
FOREACH_ELEMENT(i, table)
if (i->runlevel == runlevel) {
*isolate = i->isolate;
if (runlevel == '6' && kexec_loaded())
return SPECIAL_KEXEC_TARGET;
return table[i].special;
return i->special;
}
return NULL;

View File

@ -118,17 +118,15 @@ static void log_reset_gnutls_level(void) {
}
static int log_enable_gnutls_category(const char *cat) {
unsigned i;
if (streq(cat, "all")) {
for (i = 0; i < ELEMENTSOF(gnutls_log_map); i++)
gnutls_log_map[i].enabled = true;
FOREACH_ELEMENT(entry, gnutls_log_map)
entry->enabled = true;
log_reset_gnutls_level();
return 0;
} else
for (i = 0; i < ELEMENTSOF(gnutls_log_map); i++)
if (strv_contains((char**)gnutls_log_map[i].names, cat)) {
gnutls_log_map[i].enabled = true;
FOREACH_ELEMENT(entry, gnutls_log_map)
if (strv_contains((char**)entry->names, cat)) {
entry->enabled = true;
log_reset_gnutls_level();
return 0;
}

View File

@ -370,13 +370,12 @@ int main(int argc, char *argv[]) {
test_options(NULL);
for (unsigned i = 0; i < ELEMENTSOF(option_tests); i++)
test_options(&option_tests[i]);
FOREACH_ELEMENT(desc, option_tests)
test_options(desc);
test_option_set();
for (unsigned i = 0; i < ELEMENTSOF(option_tests); i++) {
struct option_desc *desc = &option_tests[i];
FOREACH_ELEMENT(desc, option_tests) {
if (!desc->success || desc->snamelen > 0 || desc->filelen > 0)
continue;
test_option_removal(desc);

View File

@ -4858,13 +4858,13 @@ _public_ int sd_event_dispatch(sd_event *e) {
static void event_log_delays(sd_event *e) {
char b[ELEMENTSOF(e->delays) * DECIMAL_STR_MAX(unsigned) + 1], *p;
size_t l, i;
size_t l;
p = b;
l = sizeof(b);
for (i = 0; i < ELEMENTSOF(e->delays); i++) {
l = strpcpyf(&p, l, "%u ", e->delays[i]);
e->delays[i] = 0;
FOREACH_ELEMENT(delay, e->delays) {
l = strpcpyf(&p, l, "%u ", *delay);
*delay = 0;
}
log_debug("Event loop iterations: %s", b);
}

View File

@ -42,11 +42,11 @@ TEST(set_type) {
assert_se(bus_call_method(bus, &session, "TakeControl", NULL, NULL, "b", true) >= 0);
/* All defined session types can be set */
for (size_t i = 0; i < ELEMENTSOF(types); i++) {
FOREACH_ELEMENT(i, types) {
type = mfree(type);
assert_se(bus_call_method(bus, &session, "SetType", NULL, NULL, "s", types[i]) >= 0);
assert_se(bus_call_method(bus, &session, "SetType", NULL, NULL, "s", *i) >= 0);
assert_se(bus_get_property_string(bus, &session, "Type", NULL, &type) >= 0);
assert_se(streq(type, types[i]));
assert_se(streq(type, *i));
}
/* An unknown type is rejected */

View File

@ -8,7 +8,7 @@
#include "operation.h"
#include "process-util.h"
static int operation_done_internal(const siginfo_t *si, Operation *o, sd_bus_error *error) {
static int read_operation_errno(const siginfo_t *si, Operation *o) {
int r;
assert(si);
@ -27,15 +27,6 @@ static int operation_done_internal(const siginfo_t *si, Operation *o, sd_bus_err
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Received unexpectedly short message when reading operation's errno");
}
if (o->done)
/* A completion routine is set for this operation, call it. */
return o->done(o, r, error);
/* The default operation when done is to simply return an error on failure or an empty success
* message on success. */
if (r < 0)
log_debug_errno(r, "Operation failed: %m");
return r;
}
@ -51,10 +42,18 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat
o->pid = 0;
r = read_operation_errno(si, o);
if (r < 0)
log_debug_errno(r, "Operation failed: %m");
/* If a completion routine (o->done) is set for this operation, call it. It sends a response, but can return an error in which case it expect us to reply.
* Otherwise, the default action is to simply return an error on failure or an empty success message on success. */
if (o->message) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
if (o->done)
r = o->done(o, r, &error);
r = operation_done_internal(si, o, &error);
if (r < 0) {
if (!sd_bus_error_is_set(&error))
sd_bus_error_set_errno(&error, r);
@ -62,16 +61,20 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat
r = sd_bus_reply_method_error(o->message, &error);
if (r < 0)
log_error_errno(r, "Failed to reply to dbus message: %m");
} else {
} else if (!o->done) {
/* when o->done set it's responsible for sending reply in a happy-path case */
r = sd_bus_reply_method_return(o->message, NULL);
if (r < 0)
log_error_errno(r, "Failed to reply to dbus message: %m");
}
} else if (o->link) {
r = operation_done_internal(si, o, /* error = */ NULL);
if (o->done)
r = o->done(o, r, /* error = */ NULL);
if (r < 0)
(void) sd_varlink_error_errno(o->link, r);
else
else if (!o->done)
/* when o->done set it's responsible for sending reply in a happy-path case */
(void) sd_varlink_reply(o->link, NULL);
} else
assert_not_reached();

View File

@ -635,33 +635,33 @@ int mount_all(const char *dest,
bool privileged = FLAGS_SET(mount_settings, MOUNT_PRIVILEGED);
int r;
for (size_t k = 0; k < ELEMENTSOF(mount_table); k++) {
FOREACH_ELEMENT(m, mount_table) {
_cleanup_free_ char *where = NULL, *options = NULL, *prefixed = NULL;
bool fatal = FLAGS_SET(mount_table[k].mount_settings, MOUNT_FATAL);
bool fatal = FLAGS_SET(m->mount_settings, MOUNT_FATAL);
const char *o;
/* If we are not privileged but the entry is marked as privileged and to be mounted outside the user namespace, then skip it */
if (!privileged && FLAGS_SET(mount_table[k].mount_settings, MOUNT_PRIVILEGED) && !FLAGS_SET(mount_table[k].mount_settings, MOUNT_IN_USERNS))
if (!privileged && FLAGS_SET(m->mount_settings, MOUNT_PRIVILEGED) && !FLAGS_SET(m->mount_settings, MOUNT_IN_USERNS))
continue;
if (in_userns != FLAGS_SET(mount_table[k].mount_settings, MOUNT_IN_USERNS))
if (in_userns != FLAGS_SET(m->mount_settings, MOUNT_IN_USERNS))
continue;
if (!netns && FLAGS_SET(mount_table[k].mount_settings, MOUNT_APPLY_APIVFS_NETNS))
if (!netns && FLAGS_SET(m->mount_settings, MOUNT_APPLY_APIVFS_NETNS))
continue;
if (!ro && FLAGS_SET(mount_table[k].mount_settings, MOUNT_APPLY_APIVFS_RO))
if (!ro && FLAGS_SET(m->mount_settings, MOUNT_APPLY_APIVFS_RO))
continue;
if (!tmpfs_tmp && FLAGS_SET(mount_table[k].mount_settings, MOUNT_APPLY_TMPFS_TMP))
if (!tmpfs_tmp && FLAGS_SET(m->mount_settings, MOUNT_APPLY_TMPFS_TMP))
continue;
r = chase(mount_table[k].where, dest, CHASE_NONEXISTENT|CHASE_PREFIX_ROOT, &where, NULL);
r = chase(m->where, dest, CHASE_NONEXISTENT|CHASE_PREFIX_ROOT, &where, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve %s%s: %m", strempty(dest), mount_table[k].where);
return log_error_errno(r, "Failed to resolve %s%s: %m", strempty(dest), m->where);
/* Skip this entry if it is not a remount. */
if (mount_table[k].what) {
if (m->what) {
r = path_is_mount_point(where);
if (r < 0 && r != -ENOENT)
return log_error_errno(r, "Failed to detect whether %s is a mount point: %m", where);
@ -669,10 +669,10 @@ int mount_all(const char *dest,
continue;
}
if ((mount_table[k].mount_settings & (MOUNT_MKDIR|MOUNT_TOUCH)) != 0) {
if ((m->mount_settings & (MOUNT_MKDIR|MOUNT_TOUCH)) != 0) {
uid_t u = (use_userns && !in_userns) ? uid_shift : UID_INVALID;
if (FLAGS_SET(mount_table[k].mount_settings, MOUNT_TOUCH))
if (FLAGS_SET(m->mount_settings, MOUNT_TOUCH))
r = mkdir_parents_safe(dest, where, 0755, u, u, 0);
else
r = mkdir_p_safe(dest, where, 0755, u, u, 0);
@ -689,7 +689,7 @@ int mount_all(const char *dest,
}
}
if (FLAGS_SET(mount_table[k].mount_settings, MOUNT_TOUCH)) {
if (FLAGS_SET(m->mount_settings, MOUNT_TOUCH)) {
r = touch(where);
if (r < 0 && r != -EEXIST) {
if (fatal && r != -EROFS)
@ -701,8 +701,8 @@ int mount_all(const char *dest,
}
}
o = mount_table[k].options;
if (streq_ptr(mount_table[k].type, "tmpfs")) {
o = m->options;
if (streq_ptr(m->type, "tmpfs")) {
r = tmpfs_patch_options(o, in_userns ? 0 : uid_shift, selinux_apifs_context, &options);
if (r < 0)
return log_oom();
@ -710,24 +710,24 @@ int mount_all(const char *dest,
o = options;
}
if (FLAGS_SET(mount_table[k].mount_settings, MOUNT_PREFIX_ROOT)) {
if (FLAGS_SET(m->mount_settings, MOUNT_PREFIX_ROOT)) {
/* Optionally prefix the mount source with the root dir. This is useful in bind
* mounts to be created within the container image before we transition into it. Note
* that MOUNT_IN_USERNS is run after we transitioned hence prefixing is not necessary
* for those. */
r = chase(mount_table[k].what, dest, CHASE_PREFIX_ROOT, &prefixed, NULL);
r = chase(m->what, dest, CHASE_PREFIX_ROOT, &prefixed, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve %s%s: %m", strempty(dest), mount_table[k].what);
return log_error_errno(r, "Failed to resolve %s%s: %m", strempty(dest), m->what);
}
r = mount_verbose_full(
fatal ? LOG_ERR : LOG_DEBUG,
prefixed ?: mount_table[k].what,
prefixed ?: m->what,
where,
mount_table[k].type,
mount_table[k].flags,
m->type,
m->flags,
o,
FLAGS_SET(mount_table[k].mount_settings, MOUNT_FOLLOW_SYMLINKS));
FLAGS_SET(m->mount_settings, MOUNT_FOLLOW_SYMLINKS));
if (r < 0 && fatal)
return r;
}

View File

@ -1582,11 +1582,9 @@ static int oci_seccomp_action_from_string(const char *name, uint32_t *ret) {
* here */
};
size_t i;
for (i = 0; i < ELEMENTSOF(table); i++)
if (streq_ptr(name, table[i].name)) {
*ret = table[i].action;
FOREACH_ELEMENT(i, table)
if (streq_ptr(name, i->name)) {
*ret = i->action;
return 0;
}
@ -1630,11 +1628,9 @@ static int oci_seccomp_arch_from_string(const char *name, uint32_t *ret) {
{ "SCMP_ARCH_X86_64", SCMP_ARCH_X86_64 },
};
size_t i;
for (i = 0; i < ELEMENTSOF(table); i++)
if (streq_ptr(table[i].name, name)) {
*ret = table[i].arch;
FOREACH_ELEMENT(i, table)
if (streq_ptr(i->name, name)) {
*ret = i->arch;
return 0;
}
@ -1656,11 +1652,9 @@ static int oci_seccomp_compare_from_string(const char *name, enum scmp_compare *
{ "SCMP_CMP_MASKED_EQ", SCMP_CMP_MASKED_EQ },
};
size_t i;
for (i = 0; i < ELEMENTSOF(table); i++)
if (streq_ptr(table[i].name, name)) {
*ret = table[i].op;
FOREACH_ELEMENT(i, table)
if (streq_ptr(i->name, name)) {
*ret = i->op;
return 0;
}

View File

@ -136,18 +136,18 @@ static int add_syscall_filters(
_cleanup_strv_free_ char **added = NULL;
int r;
for (size_t i = 0; i < ELEMENTSOF(allow_list); i++) {
if (allow_list[i].capability != 0 && (cap_list_retain & (1ULL << allow_list[i].capability)) == 0)
FOREACH_ELEMENT(i, allow_list) {
if (i->capability != 0 && (cap_list_retain & (1ULL << i->capability)) == 0)
continue;
r = seccomp_add_syscall_filter_item(ctx,
allow_list[i].name,
i->name,
SCMP_ACT_ALLOW,
syscall_deny_list,
false,
&added);
if (r < 0)
return log_error_errno(r, "Failed to add syscall filter item %s: %m", allow_list[i].name);
return log_error_errno(r, "Failed to add syscall filter item %s: %m", i->name);
}
STRV_FOREACH(p, syscall_allow_list) {

View File

@ -3288,17 +3288,15 @@ static int patch_sysctl(void) {
STRV_FOREACH_PAIR(k, v, arg_sysctl) {
bool good = false;
size_t i;
for (i = 0; i < ELEMENTSOF(safe_sysctl); i++) {
if (!FLAGS_SET(flags, safe_sysctl[i].clone_flags))
FOREACH_ELEMENT(i, safe_sysctl) {
if (!FLAGS_SET(flags, i->clone_flags))
continue;
if (safe_sysctl[i].prefix)
good = startswith(*k, safe_sysctl[i].key);
if (i->prefix)
good = startswith(*k, i->key);
else
good = streq(*k, safe_sysctl[i].key);
good = streq(*k, i->key);
if (good)
break;

View File

@ -1376,23 +1376,23 @@ int manager_dns_stub_start(Manager *m) {
m->dns_stub_listener_mode == DNS_STUB_LISTENER_TCP ? "TCP" :
"UDP/TCP");
for (size_t i = 0; i < ELEMENTSOF(stub_sockets); i++) {
FOREACH_ELEMENT(s, stub_sockets) {
union in_addr_union a = {
.in.s_addr = htobe32(stub_sockets[i].addr),
.in.s_addr = htobe32(s->addr),
};
if (m->dns_stub_listener_mode == DNS_STUB_LISTENER_UDP && stub_sockets[i].socket_type == SOCK_STREAM)
if (m->dns_stub_listener_mode == DNS_STUB_LISTENER_UDP && s->socket_type == SOCK_STREAM)
continue;
if (m->dns_stub_listener_mode == DNS_STUB_LISTENER_TCP && stub_sockets[i].socket_type == SOCK_DGRAM)
if (m->dns_stub_listener_mode == DNS_STUB_LISTENER_TCP && s->socket_type == SOCK_DGRAM)
continue;
r = manager_dns_stub_fd(m, AF_INET, &a, stub_sockets[i].socket_type);
r = manager_dns_stub_fd(m, AF_INET, &a, s->socket_type);
if (r < 0) {
_cleanup_free_ char *busy_socket = NULL;
if (asprintf(&busy_socket,
"%s socket " IPV4_ADDRESS_FMT_STR ":53",
stub_sockets[i].socket_type == SOCK_DGRAM ? "UDP" : "TCP",
s->socket_type == SOCK_DGRAM ? "UDP" : "TCP",
IPV4_ADDRESS_FMT_VAL(a.in)) < 0)
return log_oom();

View File

@ -235,12 +235,12 @@ static void strip_localhost(EtcHosts *hosts) {
* This way our regular synthesizing can take over, but only if it would result in the exact same
* mappings. */
for (size_t j = 0; j < ELEMENTSOF(local_in_addrs); j++) {
FOREACH_ELEMENT(local_in_addr, local_in_addrs) {
bool all_localhost, all_local_address;
EtcHostsItemByAddress *item;
const char *name;
item = hashmap_get(hosts->by_address, local_in_addrs + j);
item = hashmap_get(hosts->by_address, local_in_addr);
if (!item)
continue;
@ -284,7 +284,7 @@ static void strip_localhost(EtcHosts *hosts) {
SET_FOREACH(name, item->names)
etc_hosts_item_by_name_free(hashmap_remove(hosts->by_name, name));
assert_se(hashmap_remove(hosts->by_address, local_in_addrs + j) == item);
assert_se(hashmap_remove(hosts->by_address, local_in_addr) == item);
etc_hosts_item_by_address_free(item);
}
}

View File

@ -22,6 +22,7 @@
#include "chase.h"
#include "env-util.h"
#include "escape.h"
#include "event-util.h"
#include "exec-util.h"
#include "exit-status.h"
#include "fd-util.h"
@ -85,6 +86,7 @@ static char *arg_exec_path = NULL;
static bool arg_ignore_failure = false;
static char *arg_background = NULL;
static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF;
static char *arg_shell_prompt_prefix = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_description, freep);
STATIC_DESTRUCTOR_REGISTER(arg_environment, strv_freep);
@ -96,6 +98,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_working_directory, freep);
STATIC_DESTRUCTOR_REGISTER(arg_cmdline, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_exec_path, freep);
STATIC_DESTRUCTOR_REGISTER(arg_background, freep);
STATIC_DESTRUCTOR_REGISTER(arg_shell_prompt_prefix, freep);
static int help(void) {
_cleanup_free_ char *link = NULL;
@ -194,6 +197,7 @@ static int help_sudo_mode(void) {
" --background=COLOR Set ANSI color for background\n"
" --pty Request allocation of a pseudo TTY for stdio\n"
" --pipe Request direct pipe for stdio\n"
" --shell-prompt-prefix=PREFIX Set $SHELL_PROMPT_PREFIX\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
ansi_highlight(),
@ -778,29 +782,31 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
ARG_BACKGROUND,
ARG_PTY,
ARG_PIPE,
ARG_SHELL_PROMPT_PREFIX,
};
/* If invoked as "run0" binary, let's expose a more sudo-like interface. We add various extensions
* though (but limit the extension to long options). */
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
{ "machine", required_argument, NULL, ARG_MACHINE },
{ "unit", required_argument, NULL, ARG_UNIT },
{ "property", required_argument, NULL, ARG_PROPERTY },
{ "description", required_argument, NULL, ARG_DESCRIPTION },
{ "slice", required_argument, NULL, ARG_SLICE },
{ "slice-inherit", no_argument, NULL, ARG_SLICE_INHERIT },
{ "user", required_argument, NULL, 'u' },
{ "group", required_argument, NULL, 'g' },
{ "nice", required_argument, NULL, ARG_NICE },
{ "chdir", required_argument, NULL, 'D' },
{ "setenv", required_argument, NULL, ARG_SETENV },
{ "background", required_argument, NULL, ARG_BACKGROUND },
{ "pty", no_argument, NULL, ARG_PTY },
{ "pipe", no_argument, NULL, ARG_PIPE },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
{ "machine", required_argument, NULL, ARG_MACHINE },
{ "unit", required_argument, NULL, ARG_UNIT },
{ "property", required_argument, NULL, ARG_PROPERTY },
{ "description", required_argument, NULL, ARG_DESCRIPTION },
{ "slice", required_argument, NULL, ARG_SLICE },
{ "slice-inherit", no_argument, NULL, ARG_SLICE_INHERIT },
{ "user", required_argument, NULL, 'u' },
{ "group", required_argument, NULL, 'g' },
{ "nice", required_argument, NULL, ARG_NICE },
{ "chdir", required_argument, NULL, 'D' },
{ "setenv", required_argument, NULL, ARG_SETENV },
{ "background", required_argument, NULL, ARG_BACKGROUND },
{ "pty", no_argument, NULL, ARG_PTY },
{ "pipe", no_argument, NULL, ARG_PIPE },
{ "shell-prompt-prefix", required_argument, NULL, ARG_SHELL_PROMPT_PREFIX },
{},
};
@ -907,6 +913,12 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
arg_stdio = ARG_STDIO_DIRECT;
break;
case ARG_SHELL_PROMPT_PREFIX:
r = free_and_strdup_warn(&arg_shell_prompt_prefix, optarg);
if (r < 0)
return r;
break;
case '?':
return -EINVAL;
@ -1019,6 +1031,25 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
log_debug_errno(r, "Unable to get terminal background color, not tinting background: %m");
}
if (!arg_shell_prompt_prefix) {
const char *e = secure_getenv("SYSTEMD_RUN_SHELL_PROMPT_PREFIX");
if (e) {
arg_shell_prompt_prefix = strdup(e);
if (!arg_shell_prompt_prefix)
return log_oom();
} else if (emoji_enabled()) {
arg_shell_prompt_prefix = strjoin(special_glyph(SPECIAL_GLYPH_SUPERHERO), " ");
if (!arg_shell_prompt_prefix)
return log_oom();
}
}
if (!isempty(arg_shell_prompt_prefix)) {
r = strv_env_assign(&arg_environment, "SHELL_PROMPT_PREFIX", arg_shell_prompt_prefix);
if (r < 0)
return log_error_errno(r, "Failed to set $SHELL_PROMPT_PREFIX environment variable: %m");
}
return 1;
}
@ -1371,78 +1402,75 @@ static int transient_timer_set_properties(sd_bus_message *m) {
return 0;
}
static int make_unit_name(sd_bus *bus, UnitType t, char **ret) {
unsigned soft_reboots_count = 0;
const char *unique, *id;
char *p;
static int make_unit_name(UnitType t, char **ret) {
int r;
assert(bus);
assert(t >= 0);
assert(t < _UNIT_TYPE_MAX);
assert(ret);
r = sd_bus_get_unique_name(bus, &unique);
/* Preferably use our PID + pidfd ID as identifier, if available. It's a boot time unique identifier
* managed by the kernel. Unfortunately only new kernels support this, hence we keep some fallback
* logic in place. */
_cleanup_(pidref_done) PidRef self = PIDREF_NULL;
r = pidref_set_self(&self);
if (r < 0)
return log_error_errno(r, "Failed to get reference to my own process: %m");
r = pidref_acquire_pidfd_id(&self);
if (r < 0) {
log_debug_errno(r, "Failed to acquire pidfd ID of myself, defaulting to randomized unit name: %m");
/* We couldn't get the pidfd id. In that case, just pick a random uuid as name */
sd_id128_t rnd;
/* We couldn't get the unique name, which is a pretty
* common case if we are connected to systemd
* directly. In that case, just pick a random uuid as
* name */
r = sd_id128_randomize(&rnd);
if (r < 0)
return log_error_errno(r, "Failed to generate random run unit name: %m");
if (asprintf(ret, "run-r" SD_ID128_FORMAT_STR ".%s", SD_ID128_FORMAT_VAL(rnd), unit_type_to_string(t)) < 0)
return log_oom();
r = asprintf(ret, "run-r" SD_ID128_FORMAT_STR ".%s", SD_ID128_FORMAT_VAL(rnd), unit_type_to_string(t));
} else
r = asprintf(ret, "run-p" PID_FMT "-i%" PRIu64 ".%s", self.pid, self.fd_id, unit_type_to_string(t));
if (r < 0)
return log_oom();
return 0;
}
return 0;
}
/* We managed to get the unique name, then let's use that to name our transient units. */
static int connect_bus(sd_bus **ret) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
id = startswith(unique, ":1."); /* let' strip the usual prefix */
if (!id)
id = startswith(unique, ":"); /* the spec only requires things to start with a colon, hence
* let's add a generic fallback for that. */
if (!id)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Unique name %s has unexpected format.",
unique);
assert(ret);
/* The unique D-Bus names are actually unique per D-Bus instance, so on soft-reboot they will wrap
* and start over since the D-Bus broker is restarted. If there's a failed unit left behind that
* hasn't been garbage collected, we'll conflict. Append the soft-reboot counter to avoid clashing. */
if (arg_runtime_scope == RUNTIME_SCOPE_SYSTEM) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
r = bus_get_property_trivial(
bus, bus_systemd_mgr, "SoftRebootsCount", &error, 'u', &soft_reboots_count);
if (r < 0)
log_debug_errno(r,
"Failed to get SoftRebootsCount property, ignoring: %s",
bus_error_message(&error, r));
}
/* If --wait is used connect via the bus, unconditionally, as ref/unref is not supported via the
* limited direct connection */
if (arg_wait ||
arg_stdio != ARG_STDIO_NONE ||
(arg_runtime_scope == RUNTIME_SCOPE_USER && !IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_CAPSULE)))
r = bus_connect_transport(arg_transport, arg_host, arg_runtime_scope, &bus);
else
r = bus_connect_transport_systemd(arg_transport, arg_host, arg_runtime_scope, &bus);
if (r < 0)
return bus_log_connect_error(r, arg_transport, arg_runtime_scope);
if (soft_reboots_count > 0) {
if (asprintf(&p, "run-u%s-s%u.%s", id, soft_reboots_count, unit_type_to_string(t)) < 0)
return log_oom();
} else {
p = strjoin("run-u", id, ".", unit_type_to_string(t));
if (!p)
return log_oom();
}
(void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
*ret = p;
*ret = TAKE_PTR(bus);
return 0;
}
typedef struct RunContext {
sd_bus *bus;
sd_event *event;
PTYForward *forward;
sd_bus_slot *match;
char *service;
char *bus_path;
/* Bus objects */
sd_bus *bus;
sd_bus_slot *match_properties_changed;
sd_bus_slot *match_disconnected;
sd_event_source *retry_timer;
/* Current state of the unit */
char *active_state;
@ -1463,16 +1491,72 @@ typedef struct RunContext {
uint32_t exit_status;
} RunContext;
static void run_context_free(RunContext *c) {
static int run_context_update(RunContext *c);
static int run_context_attach_bus(RunContext *c, sd_bus *bus);
static void run_context_detach_bus(RunContext *c);
static int run_context_reconnect(RunContext *c);
static void run_context_done(RunContext *c) {
assert(c);
run_context_detach_bus(c);
c->retry_timer = sd_event_source_disable_unref(c->retry_timer);
c->forward = pty_forward_free(c->forward);
c->match = sd_bus_slot_unref(c->match);
c->bus = sd_bus_unref(c->bus);
c->event = sd_event_unref(c->event);
free(c->active_state);
free(c->result);
free(c->bus_path);
free(c->service);
}
static int on_retry_timer(sd_event_source *s, uint64_t usec, void *userdata) {
RunContext *c = ASSERT_PTR(userdata);
c->retry_timer = sd_event_source_disable_unref(c->retry_timer);
return run_context_reconnect(c);
}
static int run_context_reconnect(RunContext *c) {
int r;
assert(c);
run_context_detach_bus(c);
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
r = connect_bus(&bus);
if (r < 0) {
log_warning_errno(r, "Failed to reconnect, retrying in 2s: %m");
r = event_reset_time_relative(
c->event,
&c->retry_timer,
CLOCK_MONOTONIC,
2 * USEC_PER_SEC, /* accuracy= */ 0,
on_retry_timer, c,
SD_EVENT_PRIORITY_NORMAL,
"retry-timeout",
/* force_reset= */ false);
if (r < 0) {
(void) sd_event_exit(c->event, EXIT_FAILURE);
return log_error_errno(r, "Failed to install retry timer: %m");
}
return 0;
}
r = run_context_attach_bus(c, bus);
if (r < 0) {
(void) sd_event_exit(c->event, EXIT_FAILURE);
return r;
}
log_info("Reconnected to bus.");
return run_context_update(c);
}
static void run_context_check_done(RunContext *c) {
@ -1480,16 +1564,13 @@ static void run_context_check_done(RunContext *c) {
assert(c);
if (c->match)
done = STRPTR_IN_SET(c->active_state, "inactive", "failed") && !c->has_job;
else
done = true;
done = STRPTR_IN_SET(c->active_state, "inactive", "failed") && !c->has_job;
if (c->forward && !pty_forward_is_done(c->forward) && done) /* If the service is gone, it's time to drain the output */
done = pty_forward_drain(c->forward);
if (done)
sd_event_exit(c->event, EXIT_SUCCESS);
(void) sd_event_exit(c->event, EXIT_SUCCESS);
}
static int map_job(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
@ -1506,7 +1587,7 @@ static int map_job(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_er
return 0;
}
static int run_context_update(RunContext *c, const char *path) {
static int run_context_update(RunContext *c) {
static const struct bus_properties_map map[] = {
{ "ActiveState", "s", NULL, offsetof(RunContext, active_state) },
@ -1529,16 +1610,35 @@ static int run_context_update(RunContext *c, const char *path) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
r = bus_map_all_properties(c->bus,
"org.freedesktop.systemd1",
path,
map,
BUS_MAP_STRDUP,
&error,
NULL,
c);
assert(c);
assert(c->bus);
r = bus_map_all_properties(
c->bus,
"org.freedesktop.systemd1",
c->bus_path,
map,
BUS_MAP_STRDUP,
&error,
NULL,
c);
if (r < 0) {
sd_event_exit(c->event, EXIT_FAILURE);
/* If this is a connection error, then try to reconnect. This might be because the service
* manager is being restarted. Handle this gracefully. */
if (sd_bus_error_has_names(
&error,
SD_BUS_ERROR_NO_REPLY,
SD_BUS_ERROR_DISCONNECTED,
SD_BUS_ERROR_TIMED_OUT,
SD_BUS_ERROR_SERVICE_UNKNOWN,
SD_BUS_ERROR_NAME_HAS_NO_OWNER)) {
log_info("Bus call failed due to connection problems. Trying to reconnect...");
/* Not propagating error, because we handled it already, by reconnecting. */
return run_context_reconnect(c);
}
(void) sd_event_exit(c->event, EXIT_FAILURE);
return log_error_errno(r, "Failed to query unit state: %s", bus_error_message(&error, r));
}
@ -1547,11 +1647,67 @@ static int run_context_update(RunContext *c, const char *path) {
}
static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
RunContext *c = ASSERT_PTR(userdata);
return run_context_update(ASSERT_PTR(userdata));
}
assert(m);
static int on_disconnected(sd_bus_message *m, void *userdata, sd_bus_error *error) {
/* If our connection gets terminated, then try to reconnect. This might be because the service
* manager is being restarted. Handle this gracefully. */
log_info("Got disconnected from bus connection. Trying to reconnect...");
return run_context_reconnect(ASSERT_PTR(userdata));
}
return run_context_update(c, sd_bus_message_get_path(m));
static int run_context_attach_bus(RunContext *c, sd_bus *bus) {
int r;
assert(c);
assert(bus);
assert(!c->bus);
assert(!c->match_properties_changed);
assert(!c->match_disconnected);
c->bus = sd_bus_ref(bus);
r = sd_bus_match_signal_async(
c->bus,
&c->match_properties_changed,
"org.freedesktop.systemd1",
c->bus_path,
"org.freedesktop.DBus.Properties",
"PropertiesChanged",
on_properties_changed, NULL, c);
if (r < 0)
return log_error_errno(r, "Failed to request PropertiesChanged signal match: %m");
r = sd_bus_match_signal_async(
bus,
&c->match_disconnected,
"org.freedesktop.DBus.Local",
/* path= */ NULL,
"org.freedesktop.DBus.Local",
"Disconnected",
on_disconnected, NULL, c);
if (r < 0)
return log_error_errno(r, "Failed to request Disconnected signal match: %m");
r = sd_bus_attach_event(c->bus, c->event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
return 0;
}
static void run_context_detach_bus(RunContext *c) {
assert(c);
if (c->bus) {
(void) sd_bus_detach_event(c->bus);
c->bus = sd_bus_unref(c->bus);
}
c->match_properties_changed = sd_bus_slot_unref(c->match_properties_changed);
c->match_disconnected = sd_bus_slot_unref(c->match_disconnected);
}
static int pty_forward_handler(PTYForward *f, int rcode, void *userdata) {
@ -1567,7 +1723,7 @@ static int pty_forward_handler(PTYForward *f, int rcode, void *userdata) {
/* If --wait is specified, we'll only exit the pty forwarding, but will continue to wait
* for the service to end. If the user hits ^C we'll exit too. */
} else if (rcode < 0) {
sd_event_exit(c->event, EXIT_FAILURE);
(void) sd_event_exit(c->event, EXIT_FAILURE);
return log_error_errno(rcode, "Error on PTY forwarding logic: %m");
}
@ -1844,7 +2000,7 @@ static int start_transient_service(sd_bus *bus) {
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
} else {
r = make_unit_name(bus, UNIT_SERVICE, &service);
r = make_unit_name(UNIT_SERVICE, &service);
if (r < 0)
return r;
}
@ -1886,7 +2042,7 @@ static int start_transient_service(sd_bus *bus) {
}
if (arg_wait || arg_stdio != ARG_STDIO_NONE) {
_cleanup_(run_context_free) RunContext c = {
_cleanup_(run_context_done) RunContext c = {
.cpu_usage_nsec = NSEC_INFINITY,
.memory_peak = UINT64_MAX,
.memory_swap_peak = UINT64_MAX,
@ -1897,14 +2053,19 @@ static int start_transient_service(sd_bus *bus) {
.inactive_exit_usec = USEC_INFINITY,
.inactive_enter_usec = USEC_INFINITY,
};
_cleanup_free_ char *path = NULL;
c.bus = sd_bus_ref(bus);
r = sd_event_default(&c.event);
if (r < 0)
return log_error_errno(r, "Failed to get event loop: %m");
c.service = strdup(service);
if (!c.service)
return log_oom();
c.bus_path = unit_dbus_path_from_name(service);
if (!c.bus_path)
return log_oom();
if (master >= 0) {
(void) sd_event_set_signal_exit(c.event, true);
@ -1926,26 +2087,11 @@ static int start_transient_service(sd_bus *bus) {
set_window_title(c.forward);
}
path = unit_dbus_path_from_name(service);
if (!path)
return log_oom();
r = sd_bus_match_signal_async(
bus,
&c.match,
"org.freedesktop.systemd1",
path,
"org.freedesktop.DBus.Properties",
"PropertiesChanged",
on_properties_changed, NULL, &c);
r = run_context_attach_bus(&c, bus);
if (r < 0)
return log_error_errno(r, "Failed to request properties changed signal match: %m");
return r;
r = sd_bus_attach_event(bus, c.event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
r = run_context_update(&c, path);
r = run_context_update(&c);
if (r < 0)
return r;
@ -2059,7 +2205,7 @@ static int start_transient_scope(sd_bus *bus) {
if (r < 0)
return log_error_errno(r, "Failed to mangle scope name: %m");
} else {
r = make_unit_name(bus, UNIT_SCOPE, &scope);
r = make_unit_name(UNIT_SCOPE, &scope);
if (r < 0)
return r;
}
@ -2358,7 +2504,7 @@ static int start_transient_trigger(sd_bus *bus, const char *suffix) {
break;
}
} else {
r = make_unit_name(bus, UNIT_SERVICE, &service);
r = make_unit_name(UNIT_SERVICE, &service);
if (r < 0)
return r;
@ -2437,16 +2583,30 @@ static int run(int argc, char* argv[]) {
}
if (!arg_description) {
char *t;
_cleanup_free_ char *t = NULL;
if (strv_isempty(arg_cmdline))
t = strdup(arg_unit);
else
else if (startswith(arg_cmdline[0], "-")) {
/* Drop the login shell marker from the command line when generating the description,
* in order to minimize user confusion. */
_cleanup_strv_free_ char **l = strv_copy(arg_cmdline);
if (!l)
return log_oom();
r = free_and_strdup_warn(l + 0, l[0] + 1);
if (r < 0)
return r;
t = quote_command_line(l, SHELL_ESCAPE_EMPTY);
} else
t = quote_command_line(arg_cmdline, SHELL_ESCAPE_EMPTY);
if (!t)
return log_oom();
free_and_replace(arg_description, t);
arg_description = strjoin("[", program_invocation_short_name, "] ", t);
if (!arg_description)
return log_oom();
}
/* For backward compatibility reasons env var expansion is disabled by default for scopes, and
@ -2461,18 +2621,9 @@ static int run(int argc, char* argv[]) {
" Use --expand-environment=yes/no to explicitly control it as needed.");
}
/* If --wait is used connect via the bus, unconditionally, as ref/unref is not supported via the
* limited direct connection */
if (arg_wait ||
arg_stdio != ARG_STDIO_NONE ||
(arg_runtime_scope == RUNTIME_SCOPE_USER && !IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_CAPSULE)))
r = bus_connect_transport(arg_transport, arg_host, arg_runtime_scope, &bus);
else
r = bus_connect_transport_systemd(arg_transport, arg_host, arg_runtime_scope, &bus);
r = connect_bus(&bus);
if (r < 0)
return bus_log_connect_error(r, arg_transport, arg_runtime_scope);
(void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
return r;
if (arg_scope)
return start_transient_scope(bus);

View File

@ -760,7 +760,7 @@ int dns_name_address(const char *p, int *ret_family, union in_addr_union *ret_ad
if (r > 0) {
uint8_t a[4];
for (size_t i = 0; i < ELEMENTSOF(a); i++) {
FOREACH_ELEMENT(i, a) {
char label[DNS_LABEL_MAX+1];
r = dns_label_unescape(&p, label, sizeof label, 0);
@ -771,7 +771,7 @@ int dns_name_address(const char *p, int *ret_family, union in_addr_union *ret_ad
if (r > 3)
return -EINVAL;
r = safe_atou8(label, &a[i]);
r = safe_atou8(label, i);
if (r < 0)
return r;
}

View File

@ -48,9 +48,9 @@ int wol_options_to_string_alloc(uint32_t opts, char **ret) {
return 0;
}
for (size_t i = 0; i < ELEMENTSOF(wol_option_map); i++)
if (opts & wol_option_map[i].opt &&
!strextend_with_separator(&str, ",", wol_option_map[i].name))
FOREACH_ELEMENT(option, wol_option_map)
if (opts & option->opt &&
!strextend_with_separator(&str, ",", option->name))
return -ENOMEM;
if (!str) {
@ -1317,9 +1317,9 @@ int config_parse_wol(
if (r == 0)
break;
for (size_t i = 0; i < ELEMENTSOF(wol_option_map); i++)
if (streq(w, wol_option_map[i].name)) {
new_opts |= wol_option_map[i].opt;
FOREACH_ELEMENT(option, wol_option_map)
if (streq(w, option->name)) {
new_opts |= option->opt;
found = true;
break;
}

View File

@ -665,11 +665,11 @@ int mount_flags_to_string(unsigned long flags, char **ret) {
assert(ret);
for (size_t i = 0; i < ELEMENTSOF(map); i++)
if (flags & map[i].flag) {
if (!strextend_with_separator(&str, "|", map[i].name))
FOREACH_ELEMENT(entry, map)
if (flags & entry->flag) {
if (!strextend_with_separator(&str, "|", entry->name))
return -ENOMEM;
flags &= ~map[i].flag;
flags &= ~entry->flag;
}
if (!str || flags != 0)

View File

@ -35,9 +35,9 @@ const NamingScheme* naming_scheme_from_name(const char *name) {
* the table like any other name. After iterating through the table, we check for "latest" again,
* which means that if not mapped explicitly, it maps to the last defined entry, whatever that is. */
for (size_t i = 0; i < ELEMENTSOF(naming_schemes); i++)
if (streq(naming_schemes[i].name, name))
return naming_schemes + i;
FOREACH_ELEMENT(scheme, naming_schemes)
if (streq(scheme->name, name))
return scheme;
if (streq(name, "latest"))
return naming_schemes + ELEMENTSOF(naming_schemes) - 1;

View File

@ -1734,14 +1734,13 @@ int seccomp_restrict_realtime_full(int error_code) {
int r, max_policy = 0;
uint32_t arch;
unsigned i;
assert(error_code > 0);
/* Determine the highest policy constant we want to allow */
for (i = 0; i < ELEMENTSOF(permitted_policies); i++)
if (permitted_policies[i] > max_policy)
max_policy = permitted_policies[i];
FOREACH_ELEMENT(policy, permitted_policies)
if (*policy > max_policy)
max_policy = *policy;
SECCOMP_FOREACH_LOCAL_ARCH(arch) {
_cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
@ -1759,8 +1758,8 @@ int seccomp_restrict_realtime_full(int error_code) {
bool good = false;
/* Check if this is in the allow list. */
for (i = 0; i < ELEMENTSOF(permitted_policies); i++)
if (permitted_policies[i] == p) {
FOREACH_ELEMENT(policy, permitted_policies)
if (*policy == p) {
good = true;
break;
}

View File

@ -1483,34 +1483,34 @@ int user_group_record_mangle(
return json_log(v, json_flags, SYNTHETIC_ERRNO(EINVAL), "Stripping everything from record, refusing.");
/* Check if we have the special sections and if they match our flags set */
for (size_t i = 0; i < ELEMENTSOF(mask_field); i++) {
FOREACH_ELEMENT(i, mask_field) {
sd_json_variant *e, *k;
if (FLAGS_SET(USER_RECORD_STRIP_MASK(load_flags), mask_field[i].mask)) {
if (FLAGS_SET(USER_RECORD_STRIP_MASK(load_flags), i->mask)) {
if (!w)
w = sd_json_variant_ref(v);
r = sd_json_variant_filter(&w, STRV_MAKE(mask_field[i].name));
r = sd_json_variant_filter(&w, STRV_MAKE(i->name));
if (r < 0)
return json_log(w, json_flags, r, "Failed to remove field from variant: %m");
continue;
}
e = sd_json_variant_by_key_full(v, mask_field[i].name, &k);
e = sd_json_variant_by_key_full(v, i->name, &k);
if (e) {
if (!FLAGS_SET(USER_RECORD_ALLOW_MASK(load_flags), mask_field[i].mask))
return json_log(e, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record contains '%s' field, which is not allowed.", mask_field[i].name);
if (!FLAGS_SET(USER_RECORD_ALLOW_MASK(load_flags), i->mask))
return json_log(e, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record contains '%s' field, which is not allowed.", i->name);
if (FLAGS_SET(load_flags, USER_RECORD_STRIP_REGULAR)) {
array[n_retain++] = k;
array[n_retain++] = e;
}
m |= mask_field[i].mask;
m |= i->mask;
} else {
if (FLAGS_SET(USER_RECORD_REQUIRE_MASK(load_flags), mask_field[i].mask))
return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record lacks '%s' field, which is required.", mask_field[i].name);
if (FLAGS_SET(USER_RECORD_REQUIRE_MASK(load_flags), i->mask))
return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record lacks '%s' field, which is required.", i->name);
}
}
@ -1530,8 +1530,8 @@ int user_group_record_mangle(
assert_se(f = sd_json_variant_string(sd_json_variant_by_index(v, i)));
for (size_t j = 0; j < ELEMENTSOF(mask_field); j++)
if (streq(f, mask_field[j].name)) { /* already covered in the loop above */
FOREACH_ELEMENT(j, mask_field)
if (streq(f, j->name)) { /* already covered in the loop above */
special = true;
continue;
}

View File

@ -65,13 +65,13 @@ TEST_RET(bootspec_sort) {
ASSERT_OK(mkdtemp_malloc("/tmp/bootspec-testXXXXXX", &d));
for (size_t i = 0; i < ELEMENTSOF(entries); i++) {
FOREACH_ELEMENT(entry, entries) {
_cleanup_free_ char *j = NULL;
j = path_join(d, "/loader/entries/", entries[i].fname);
j = path_join(d, "/loader/entries/", entry->fname);
assert_se(j);
ASSERT_OK(write_string_file(j, entries[i].contents, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755));
ASSERT_OK(write_string_file(j, entry->contents, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755));
}
ASSERT_OK(boot_config_load(&config, d, NULL));
@ -176,13 +176,13 @@ TEST_RET(bootspec_boot_config_find_entry) {
assert_se(mkdtemp_malloc("/tmp/bootspec-testXXXXXX", &d) >= 0);
for (size_t i = 0; i < ELEMENTSOF(entries); i++) {
FOREACH_ELEMENT(entry, entries) {
_cleanup_free_ char *j = NULL;
j = path_join(d, "/loader/entries/", entries[i].fname);
j = path_join(d, "/loader/entries/", entry->fname);
assert_se(j);
assert_se(write_string_file(j, entries[i].contents, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) >= 0);
assert_se(write_string_file(j, entry->contents, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) >= 0);
}
assert_se(boot_config_load(&config, d, NULL) >= 0);

View File

@ -46,8 +46,8 @@ static int parse_argv(int argc, char *argv[]) {
" %s [OPTION...] path...\n"
"Options:\n"
, argv[0]);
for (size_t i = 0; i < ELEMENTSOF(options) - 1; i++)
printf(" --%s\n", options[i].name);
FOREACH_ARRAY(option, options, ELEMENTSOF(options) - 1)
printf(" --%s\n", option->name);
return 0;
case ARG_ROOT:

View File

@ -892,14 +892,14 @@ TEST(read_line4) {
int r;
for (size_t i = 0; i < ELEMENTSOF(eof_endings); i++) {
FOREACH_ELEMENT(ending, eof_endings) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *s = NULL;
assert_se(f = fmemopen_unlocked((void*) eof_endings[i].string, eof_endings[i].length, "r"));
assert_se(f = fmemopen_unlocked((void*) ending->string, ending->length, "r"));
r = read_line(f, SIZE_MAX, &s);
assert_se((size_t) r == eof_endings[i].length);
assert_se((size_t) r == ending->length);
ASSERT_STREQ(s, "foo");
assert_se(read_line(f, SIZE_MAX, NULL) == 0); /* Ensure we hit EOF */

View File

@ -688,7 +688,7 @@ static const struct hash_ops crippled_hashmap_ops = {
TEST(hashmap_many) {
Hashmap *h;
unsigned i, j;
unsigned i;
void *v, *k;
bool slow = slow_tests_enabled();
const struct {
@ -702,24 +702,24 @@ TEST(hashmap_many) {
log_info("/* %s (%s) */", __func__, slow ? "slow" : "fast");
for (j = 0; j < ELEMENTSOF(tests); j++) {
FOREACH_ELEMENT(test, tests) {
usec_t ts = now(CLOCK_MONOTONIC), n;
assert_se(h = hashmap_new(tests[j].ops));
assert_se(h = hashmap_new(test->ops));
for (i = 1; i < tests[j].n_entries*3; i+=3) {
for (i = 1; i < test->n_entries*3; i+=3) {
assert_se(hashmap_put(h, UINT_TO_PTR(i), UINT_TO_PTR(i)) >= 0);
assert_se(PTR_TO_UINT(hashmap_get(h, UINT_TO_PTR(i))) == i);
}
for (i = 1; i < tests[j].n_entries*3; i++)
for (i = 1; i < test->n_entries*3; i++)
assert_se(hashmap_contains(h, UINT_TO_PTR(i)) == (i % 3 == 1));
log_info("%s %u <= %u * 0.8 = %g",
tests[j].title, hashmap_size(h), hashmap_buckets(h), hashmap_buckets(h) * 0.8);
test->title, hashmap_size(h), hashmap_buckets(h), hashmap_buckets(h) * 0.8);
assert_se(hashmap_size(h) <= hashmap_buckets(h) * 0.8);
assert_se(hashmap_size(h) == tests[j].n_entries);
assert_se(hashmap_size(h) == test->n_entries);
while (!hashmap_isempty(h)) {
k = hashmap_first_key(h);
@ -754,9 +754,9 @@ TEST(hashmap_free) {
log_info("/* %s (%s, %u entries) */", __func__, slow ? "slow" : "fast", n_entries);
for (unsigned j = 0; j < ELEMENTSOF(tests); j++) {
FOREACH_ELEMENT(test, tests) {
ts = now(CLOCK_MONOTONIC);
assert_se(h = hashmap_new(tests[j].ops));
assert_se(h = hashmap_new(test->ops));
custom_counter = 0;
for (unsigned i = 0; i < n_entries; i++) {
@ -774,9 +774,9 @@ TEST(hashmap_free) {
hashmap_free(h);
n = now(CLOCK_MONOTONIC);
log_info("%s test took %s", tests[j].title, FORMAT_TIMESPAN(n - ts, 0));
log_info("%s test took %s", test->title, FORMAT_TIMESPAN(n - ts, 0));
assert_se(custom_counter == tests[j].expect_counter);
assert_se(custom_counter == test->expect_counter);
}
}

View File

@ -11,12 +11,12 @@ int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
for (size_t i = 0; i < ELEMENTSOF(test_states); i++) {
FOREACH_ELEMENT(state, test_states) {
/* fake a unit */
Service s = {
.meta.load_state = UNIT_LOADED,
.type = SERVICE_SIMPLE,
.state = test_states[i],
.state = *state,
};
Unit *u = UNIT(&s);

View File

@ -20,10 +20,10 @@ int main(int argc, const char *argv[]) {
ASSERT_NULL(head);
ASSERT_NULL(head2);
for (i = 0; i < ELEMENTSOF(items); i++) {
LIST_INIT(item_list, &items[i]);
assert_se(LIST_JUST_US(item_list, &items[i]));
assert_se(LIST_PREPEND(item_list, head, &items[i]) == &items[i]);
FOREACH_ELEMENT(item, items) {
LIST_INIT(item_list, item);
assert_se(LIST_JUST_US(item_list, item));
assert_se(LIST_PREPEND(item_list, head, item) == item);
}
i = 0;
@ -183,9 +183,9 @@ int main(int argc, const char *argv[]) {
ASSERT_NULL(head);
for (i = 0; i < ELEMENTSOF(items); i++) {
assert_se(LIST_JUST_US(item_list, &items[i]));
assert_se(LIST_APPEND(item_list, head, &items[i]) == &items[i]);
FOREACH_ELEMENT(item, items) {
assert_se(LIST_JUST_US(item_list, item));
assert_se(LIST_APPEND(item_list, head, item) == item);
}
assert_se(!LIST_JUST_US(item_list, head));
@ -200,15 +200,15 @@ int main(int argc, const char *argv[]) {
assert_se(items[2].item_list_prev == &items[1]);
assert_se(items[3].item_list_prev == &items[2]);
for (i = 0; i < ELEMENTSOF(items); i++)
assert_se(LIST_REMOVE(item_list, head, &items[i]) == &items[i]);
FOREACH_ELEMENT(item, items)
assert_se(LIST_REMOVE(item_list, head, item) == item);
ASSERT_NULL(head);
for (i = 0; i < ELEMENTSOF(items) / 2; i++) {
LIST_INIT(item_list, &items[i]);
assert_se(LIST_JUST_US(item_list, &items[i]));
assert_se(LIST_PREPEND(item_list, head, &items[i]) == &items[i]);
FOREACH_ARRAY(item, items, ELEMENTSOF(items) / 2) {
LIST_INIT(item_list, item);
assert_se(LIST_JUST_US(item_list, item));
assert_se(LIST_PREPEND(item_list, head, item) == item);
}
for (i = ELEMENTSOF(items) / 2; i < ELEMENTSOF(items); i++) {
@ -244,8 +244,8 @@ int main(int argc, const char *argv[]) {
ASSERT_NULL(head2);
assert_se(head);
for (i = 0; i < ELEMENTSOF(items); i++)
assert_se(LIST_REMOVE(item_list, head, &items[i]) == &items[i]);
FOREACH_ELEMENT(item, items)
assert_se(LIST_REMOVE(item_list, head, item) == item);
ASSERT_NULL(head);

View File

@ -912,22 +912,21 @@ TEST(config_parse_memory_limit) {
{ "MemoryMax", "10", &c.memory_max, 10 },
{ "MemoryMax", "infinity", &c.memory_max, CGROUP_LIMIT_MAX },
};
size_t i;
int r;
for (i = 0; i < ELEMENTSOF(limit_tests); i++) {
FOREACH_ELEMENT(test, limit_tests) {
c.memory_min = CGROUP_LIMIT_DUMMY;
c.memory_low = CGROUP_LIMIT_DUMMY;
c.memory_high = CGROUP_LIMIT_DUMMY;
c.memory_max = CGROUP_LIMIT_DUMMY;
r = config_parse_memory_limit(NULL, "fake", 1, "section", 1,
limit_tests[i].limit, 1,
limit_tests[i].value, &c, NULL);
test->limit, 1,
test->value, &c, NULL);
log_info("%s=%s\t%"PRIu64"==%"PRIu64,
limit_tests[i].limit, limit_tests[i].value,
*limit_tests[i].result, limit_tests[i].expected);
test->limit, test->value,
*test->result, test->expected);
assert_se(r >= 0);
assert_se(*limit_tests[i].result == limit_tests[i].expected);
assert_se(*test->result == test->expected);
}
}
@ -1029,12 +1028,12 @@ TEST(config_parse_log_filter_patterns) {
if (ERRNO_IS_NOT_SUPPORTED(dlopen_pcre2()))
return (void) log_tests_skipped("PCRE2 support is not available");
for (size_t i = 0; i < ELEMENTSOF(regex_tests); i++) {
FOREACH_ELEMENT(test, regex_tests) {
assert_se(config_parse_log_filter_patterns(NULL, "fake", 1, "section", 1, "LogFilterPatterns", 1,
regex_tests[i].regex, &c, NULL) >= 0);
test->regex, &c, NULL) >= 0);
assert_se(set_size(c.log_filter_allowed_patterns) == regex_tests[i].allowed_patterns_count);
assert_se(set_size(c.log_filter_denied_patterns) == regex_tests[i].denied_patterns_count);
assert_se(set_size(c.log_filter_allowed_patterns) == test->allowed_patterns_count);
assert_se(set_size(c.log_filter_denied_patterns) == test->denied_patterns_count);
/* Ensure `~` is properly removed */
const char *p;

View File

@ -82,7 +82,7 @@ TEST(keymaps) {
#define dump_glyph(x) log_info(STRINGIFY(x) ": %s", special_glyph(x))
TEST(dump_special_glyphs) {
assert_cc(SPECIAL_GLYPH_GREEN_CIRCLE + 1 == _SPECIAL_GLYPH_MAX);
assert_cc(SPECIAL_GLYPH_SUPERHERO + 1 == _SPECIAL_GLYPH_MAX);
log_info("is_locale_utf8: %s", yes_no(is_locale_utf8()));
@ -133,6 +133,7 @@ TEST(dump_special_glyphs) {
dump_glyph(SPECIAL_GLYPH_YELLOW_CIRCLE);
dump_glyph(SPECIAL_GLYPH_BLUE_CIRCLE);
dump_glyph(SPECIAL_GLYPH_GREEN_CIRCLE);
dump_glyph(SPECIAL_GLYPH_SUPERHERO);
}
DEFINE_TEST_MAIN(LOG_INFO);

View File

@ -46,11 +46,11 @@ TEST(set_free_with_hash_ops) {
assert_se(m = ordered_set_new(&item_hash_ops));
for (size_t i = 0; i < ELEMENTSOF(items) - 1; i++)
assert_se(ordered_set_put(m, items + i) == 1);
FOREACH_ARRAY(item, items, ELEMENTSOF(items) - 1)
assert_se(ordered_set_put(m, item) == 1);
for (size_t i = 0; i < ELEMENTSOF(items) - 1; i++)
assert_se(ordered_set_put(m, items + i) == 0); /* We get 0 here, because we use trivial hash
FOREACH_ARRAY(item, items, ELEMENTSOF(items) - 1)
assert_se(ordered_set_put(m, item) == 0); /* We get 0 here, because we use trivial hash
* ops. Also see below... */
m = ordered_set_free(m);

View File

@ -17,15 +17,15 @@ static int unsigned_compare(const unsigned *a, const unsigned *b) {
TEST(unsigned) {
_cleanup_(prioq_freep) Prioq *q = NULL;
unsigned buffer[SET_SIZE], i, u, n;
unsigned buffer[SET_SIZE], u, n;
srand(0);
assert_se(q = prioq_new(trivial_compare_func));
for (i = 0; i < ELEMENTSOF(buffer); i++) {
FOREACH_ELEMENT(i, buffer) {
u = (unsigned) rand();
buffer[i] = u;
*i = u;
assert_se(prioq_put(q, UINT_TO_PTR(u), NULL) >= 0);
n = prioq_size(q);
@ -34,7 +34,7 @@ TEST(unsigned) {
typesafe_qsort(buffer, ELEMENTSOF(buffer), unsigned_compare);
for (i = 0; i < ELEMENTSOF(buffer); i++) {
for (unsigned i = 0; i < ELEMENTSOF(buffer); i++) {
assert_se(prioq_size(q) == ELEMENTSOF(buffer) - i);
u = PTR_TO_UINT(prioq_pop(q));

View File

@ -37,8 +37,8 @@ TEST(set_free_with_destructor) {
struct Item items[4] = {};
assert_se(m = set_new(NULL));
for (size_t i = 0; i < ELEMENTSOF(items) - 1; i++)
assert_se(set_put(m, items + i) == 1);
FOREACH_ARRAY(item, items, ELEMENTSOF(items) - 1)
assert_se(set_put(m, item) == 1);
m = set_free_with_destructor(m, item_seen);
assert_se(items[0].seen == 1);
@ -54,8 +54,8 @@ TEST(set_free_with_hash_ops) {
struct Item items[4] = {};
assert_se(m = set_new(&item_hash_ops));
for (size_t i = 0; i < ELEMENTSOF(items) - 1; i++)
assert_se(set_put(m, items + i) == 1);
FOREACH_ARRAY(item, items, ELEMENTSOF(items) - 1)
assert_se(set_put(m, item) == 1);
m = set_free(m);
assert_se(items[0].seen == 1);

View File

@ -80,10 +80,10 @@ TEST(free_and_strndup) {
_cleanup_free_ char *t = NULL;
const char *prev_expected = t;
for (unsigned i = 0; i < ELEMENTSOF(cases); i++) {
FOREACH_ELEMENT(c, cases) {
test_free_and_strndup_one(&t,
cases[i].src, cases[i].len, cases[i].expected,
!streq_ptr(cases[i].expected, prev_expected));
c->src, c->len, c->expected,
!streq_ptr(c->expected, prev_expected));
prev_expected = t;
}
}

View File

@ -126,8 +126,8 @@ static const Color colors[] = {
};
TEST(colors) {
for (size_t i = 0; i < ELEMENTSOF(colors); i++)
printf("<%s%s%s>\n", colors[i].func(), colors[i].name, ansi_normal());
FOREACH_ELEMENT(color, colors)
printf("<%s%s%s>\n", colors->func(), color->name, ansi_normal());
}
TEST(text) {

View File

@ -152,8 +152,8 @@ static void _test_pcr_selection_mask_hash(uint32_t mask, TPMI_ALG_HASH hash) {
uint32_t test_masks[] = {
0x0, 0x1, 0x100, 0x10000, 0xf0f0f0, 0xaaaaaa, 0xffffff,
};
for (unsigned i = 0; i < ELEMENTSOF(test_masks); i++) {
uint32_t test_mask = test_masks[i];
FOREACH_ELEMENT(i, test_masks) {
uint32_t test_mask = *i;
TPMS_PCR_SELECTION a = POISON_TPMS, b = POISON_TPMS, test_s = POISON_TPMS;
tpm2_tpms_pcr_selection_from_mask(test_mask, hash, &test_s);
@ -181,11 +181,11 @@ static void _test_pcr_selection_mask_hash(uint32_t mask, TPMI_ALG_HASH hash) {
TEST(tpms_pcr_selection_mask_and_hash) {
TPMI_ALG_HASH HASH_ALGS[] = { TPM2_ALG_SHA1, TPM2_ALG_SHA256, };
for (unsigned i = 0; i < ELEMENTSOF(HASH_ALGS); i++)
FOREACH_ELEMENT(hash, HASH_ALGS)
for (uint32_t m2 = 0; m2 <= 0xffffff; m2 += 0x50000)
for (uint32_t m1 = 0; m1 <= 0xffff; m1 += 0x500)
for (uint32_t m0 = 0; m0 <= 0xff; m0 += 0x5)
_test_pcr_selection_mask_hash(m0 | m1 | m2, HASH_ALGS[i]);
_test_pcr_selection_mask_hash(m0 | m1 | m2, *hash);
}
static void _test_tpms_sw(
@ -1191,11 +1191,9 @@ static int check_calculate_seal(Tpm2Context *c) {
calculate_seal_and_unseal(c, TPM2_SRK_HANDLE, srk_public);
TPMI_ALG_ASYM test_algs[] = { TPM2_ALG_RSA, TPM2_ALG_ECC, };
for (unsigned i = 0; i < ELEMENTSOF(test_algs); i++) {
TPMI_ALG_ASYM alg = test_algs[i];
FOREACH_ELEMENT(alg, test_algs) {
TPM2B_PUBLIC template = { .size = sizeof(TPMT_PUBLIC), };
assert_se(tpm2_get_srk_template(alg, &template.publicArea) >= 0);
assert_se(tpm2_get_srk_template(*alg, &template.publicArea) >= 0);
_cleanup_free_ TPM2B_PUBLIC *public = NULL;
_cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;

View File

@ -335,8 +335,8 @@ static bool manager_sample_spike_detection(Manager *m, double offset, double del
idx_min = i;
j = 0;
for (i = 0; i < ELEMENTSOF(m->samples); i++)
j += pow(m->samples[i].offset - m->samples[idx_min].offset, 2);
FOREACH_ELEMENT(sample, m->samples)
j += pow(sample->offset - m->samples[idx_min].offset, 2);
m->samples_jitter = sqrt(j / (ELEMENTSOF(m->samples) - 1));
/* ignore samples when resyncing */

View File

@ -228,7 +228,6 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) {
_cleanup_hashmap_free_ Hashmap *stats_by_path = NULL;
_cleanup_free_ char *name = NULL;
const char *dropin_dirname;
size_t i;
int r;
assert(ctx);
@ -267,8 +266,8 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) {
.sr_iov_num_vfs = UINT32_MAX,
};
for (i = 0; i < ELEMENTSOF(config->features); i++)
config->features[i] = -1;
FOREACH_ELEMENT(feature, config->features)
*feature = -1;
dropin_dirname = strjoina(basename(filename), ".d");
r = config_parse_many(

View File

@ -76,10 +76,10 @@ static int fake_filesystems(void) {
if (r < 0)
return log_error_errno(r, "Failed to detach mount namespace: %m");
for (size_t i = 0; i < ELEMENTSOF(fakefss); i++) {
r = mount_nofollow_verbose(fakefss[i].ignore_mount_error ? LOG_NOTICE : LOG_ERR,
fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL);
if (r < 0 && !fakefss[i].ignore_mount_error)
FOREACH_ELEMENT(fakefs, fakefss) {
r = mount_nofollow_verbose(fakefs->ignore_mount_error ? LOG_NOTICE : LOG_ERR,
fakefs->src, fakefs->target, NULL, MS_BIND, NULL);
if (r < 0 && !fakefs->ignore_mount_error)
return r;
}

View File

@ -295,8 +295,8 @@ static bool test_pointers(
size_t num_well_known_keys = 0;
if (has_keys)
for (size_t i = 0; i < ELEMENTSOF(well_known_keyboard_keys); i++)
if (test_bit(well_known_keyboard_keys[i], bitmask_key))
FOREACH_ELEMENT(key, well_known_keyboard_keys)
if (test_bit(*key, bitmask_key))
num_well_known_keys++;
if (num_well_known_keys >= 4 || num_joystick_buttons + num_joystick_axes < 2) {

View File

@ -58,16 +58,16 @@ static const struct subst_map_entry map[] = {
};
static const char *format_type_to_string(FormatSubstitutionType t) {
for (size_t i = 0; i < ELEMENTSOF(map); i++)
if (map[i].type == t)
return map[i].name;
FOREACH_ELEMENT(entry, map)
if (entry->type == t)
return entry->name;
return NULL;
}
static char format_type_to_char(FormatSubstitutionType t) {
for (size_t i = 0; i < ELEMENTSOF(map); i++)
if (map[i].type == t)
return map[i].fmt;
FOREACH_ELEMENT(entry, map)
if (entry->type == t)
return entry->fmt;
return '\0';
}

View File

@ -31,7 +31,6 @@ static int help(void) {
};
_cleanup_free_ char *link = NULL;
size_t i;
int r;
r = terminal_urlify_man("udevadm", "8", &link);
@ -43,8 +42,8 @@ static int help(void) {
"Commands:\n",
program_invocation_short_name);
for (i = 0; i < ELEMENTSOF(short_descriptions); i++)
printf(" %-12s %s\n", short_descriptions[i][0], short_descriptions[i][1]);
FOREACH_ELEMENT(desc, short_descriptions)
printf(" %-12s %s\n", (*desc)[0], (*desc)[1]);
printf("\nSee the %s for details.\n", link);
return 0;

View File

@ -272,3 +272,6 @@ if [[ -e /usr/lib/pam.d/systemd-run0 ]] || [[ -e /etc/pam.d/systemd-run0 ]]; the
assert_neq "$(run0 --pty tty < /dev/null)" "not a tty"
assert_eq "$(run0 --pipe tty < /dev/null)" "not a tty"
fi
# Tests whether intermediate disconnects corrupt us (modified testcase from https://github.com/systemd/systemd/issues/27204)
assert_rc "37" systemd-run --unit=disconnecttest --wait --pipe --user -M testuser@.host bash -ec 'systemctl --user daemon-reexec; sleep 3; exit 37'