mirror of
https://github.com/systemd/systemd.git
synced 2024-10-26 08:55:40 +03:00
Compare commits
17 Commits
86a221ac46
...
89aaac715b
Author | SHA1 | Date | |
---|---|---|---|
|
89aaac715b | ||
|
d541dd8bbd | ||
|
f7078de515 | ||
|
6d6048b4cb | ||
|
10a48938ef | ||
|
b58b13f1c6 | ||
|
c8f59296bf | ||
|
d585085f57 | ||
|
ff4b6a1915 | ||
|
d9f68f48f7 | ||
|
0310b2a60b | ||
|
115fac3c29 | ||
|
9d8f5e22f8 | ||
|
6fb0c52295 | ||
|
edd10ab29c | ||
|
988053eac3 | ||
|
8049370515 |
3
TODO
3
TODO
@ -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().
|
||||
|
52
man/run0.xml
52
man/run0.xml
@ -192,6 +192,35 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--pty</option></term>
|
||||
<term><option>--pipe</option></term>
|
||||
|
||||
<listitem><para>Request allocation of a pseudo TTY for the <command>run0</command> session (in case
|
||||
of <option>--pty</option>), or request passing the caller's STDIO file descriptors directly through
|
||||
(in case of <option>--pipe</option>). If neither switch is specified, or if both switches are
|
||||
specified, the mode will be picked automatically: if standard input, standard output and standard
|
||||
error output are all connected to a TTY then a pseudo TTY is allocated, otherwise the relevant file
|
||||
descriptors are passed through directly.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v257"/>
|
||||
</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>
|
||||
|
||||
@ -256,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>
|
||||
|
@ -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;
|
||||
|
@ -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"🦸",
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -290,7 +290,7 @@ static int handle_arg_console(const char *arg) {
|
||||
else if (streq(arg, "passive"))
|
||||
arg_console_mode = CONSOLE_PASSIVE;
|
||||
else if (streq(arg, "pipe")) {
|
||||
if (isatty_safe(STDIN_FILENO) && isatty(STDOUT_FILENO))
|
||||
if (isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO))
|
||||
log_full(arg_quiet ? LOG_DEBUG : LOG_NOTICE,
|
||||
"Console mode 'pipe' selected, but standard input/output are connected to an interactive TTY. "
|
||||
"Most likely you want to use 'interactive' console mode for proper interactivity and shell job control. "
|
||||
@ -298,7 +298,7 @@ static int handle_arg_console(const char *arg) {
|
||||
|
||||
arg_console_mode = CONSOLE_PIPE;
|
||||
} else if (streq(arg, "autopipe")) {
|
||||
if (isatty_safe(STDIN_FILENO) && isatty(STDOUT_FILENO))
|
||||
if (isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO))
|
||||
arg_console_mode = CONSOLE_INTERACTIVE;
|
||||
else
|
||||
arg_console_mode = CONSOLE_PIPE;
|
||||
@ -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;
|
||||
@ -5981,7 +5979,7 @@ static int run(int argc, char *argv[]) {
|
||||
umask(0022);
|
||||
|
||||
if (arg_console_mode < 0)
|
||||
arg_console_mode = isatty_safe(STDIN_FILENO) && isatty(STDOUT_FILENO) ?
|
||||
arg_console_mode = isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO) ?
|
||||
CONSOLE_INTERACTIVE : CONSOLE_READ_ONLY;
|
||||
|
||||
if (arg_console_mode == CONSOLE_PIPE) /* if we pass STDERR on to the container, don't add our own logs into it too */
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
379
src/run/run.c
379
src/run/run.c
@ -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;
|
||||
@ -171,6 +174,10 @@ static int help_sudo_mode(void) {
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
/* NB: Let's not go overboard with short options: we try to keep a modicum of compatibility with
|
||||
* sudo's short switches, hence please do not introduce new short switches unless they have a roughly
|
||||
* equivalent purpose on sudo. Use long options for everything private to run0. */
|
||||
|
||||
printf("%s [OPTIONS...] COMMAND [ARGUMENTS...]\n"
|
||||
"\n%sElevate privileges interactively.%s\n\n"
|
||||
" -h --help Show this help\n"
|
||||
@ -188,6 +195,9 @@ static int help_sudo_mode(void) {
|
||||
" -D --chdir=PATH Set working directory\n"
|
||||
" --setenv=NAME[=VALUE] Set environment variable\n"
|
||||
" --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(),
|
||||
@ -674,7 +684,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
/* If we both --pty and --pipe are specified we'll automatically pick --pty if we are connected fully
|
||||
* to a TTY and pick direct fd passing otherwise. This way, we automatically adapt to usage in a shell
|
||||
* pipeline, but we are neatly interactive with tty-level isolation otherwise. */
|
||||
arg_stdio = isatty_safe(STDIN_FILENO) && isatty(STDOUT_FILENO) && isatty(STDERR_FILENO) ?
|
||||
arg_stdio = isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO) && isatty_safe(STDERR_FILENO) ?
|
||||
ARG_STDIO_PTY :
|
||||
ARG_STDIO_DIRECT;
|
||||
|
||||
@ -770,6 +780,9 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
ARG_NICE,
|
||||
ARG_SETENV,
|
||||
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
|
||||
@ -791,6 +804,9 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
{ "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 },
|
||||
{},
|
||||
};
|
||||
|
||||
@ -883,6 +899,26 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
|
||||
break;
|
||||
|
||||
case ARG_PTY:
|
||||
if (IN_SET(arg_stdio, ARG_STDIO_DIRECT, ARG_STDIO_AUTO)) /* if --pipe is already used, upgrade to auto mode */
|
||||
arg_stdio = ARG_STDIO_AUTO;
|
||||
else
|
||||
arg_stdio = ARG_STDIO_PTY;
|
||||
break;
|
||||
|
||||
case ARG_PIPE:
|
||||
if (IN_SET(arg_stdio, ARG_STDIO_PTY, ARG_STDIO_AUTO)) /* If --pty is already used, upgrade to auto mode */
|
||||
arg_stdio = ARG_STDIO_AUTO;
|
||||
else
|
||||
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;
|
||||
|
||||
@ -913,7 +949,9 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
arg_wait = true;
|
||||
arg_aggressive_gc = true;
|
||||
|
||||
arg_stdio = isatty_safe(STDIN_FILENO) && isatty(STDOUT_FILENO) && isatty(STDERR_FILENO) ? ARG_STDIO_PTY : ARG_STDIO_DIRECT;
|
||||
if (IN_SET(arg_stdio, ARG_STDIO_NONE, ARG_STDIO_AUTO))
|
||||
arg_stdio = isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO) && isatty_safe(STDERR_FILENO) ? ARG_STDIO_PTY : ARG_STDIO_DIRECT;
|
||||
|
||||
arg_expand_environment = false;
|
||||
arg_send_sighup = true;
|
||||
|
||||
@ -993,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;
|
||||
}
|
||||
|
||||
@ -1181,7 +1238,7 @@ static int transient_service_set_properties(sd_bus_message *m, const char *pty_p
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
send_term = isatty_safe(STDIN_FILENO) || isatty(STDOUT_FILENO) || isatty(STDERR_FILENO);
|
||||
send_term = isatty_safe(STDIN_FILENO) || isatty_safe(STDOUT_FILENO) || isatty_safe(STDERR_FILENO);
|
||||
}
|
||||
|
||||
if (send_term) {
|
||||
@ -1345,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)
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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 --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)
|
||||
log_debug_errno(r,
|
||||
"Failed to get SoftRebootsCount property, ignoring: %s",
|
||||
bus_error_message(&error, r));
|
||||
}
|
||||
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;
|
||||
@ -1437,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) {
|
||||
@ -1454,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;
|
||||
|
||||
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) {
|
||||
@ -1480,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) },
|
||||
@ -1503,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,
|
||||
assert(c);
|
||||
assert(c->bus);
|
||||
|
||||
r = bus_map_all_properties(
|
||||
c->bus,
|
||||
"org.freedesktop.systemd1",
|
||||
path,
|
||||
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));
|
||||
}
|
||||
|
||||
@ -1521,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) {
|
||||
@ -1541,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");
|
||||
}
|
||||
|
||||
@ -1818,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;
|
||||
}
|
||||
@ -1860,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,
|
||||
@ -1871,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);
|
||||
|
||||
@ -1900,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;
|
||||
|
||||
@ -2033,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;
|
||||
}
|
||||
@ -2332,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;
|
||||
|
||||
@ -2411,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
|
||||
@ -2435,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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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';
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -261,4 +261,17 @@ if [[ -e /usr/lib/pam.d/systemd-run0 ]] || [[ -e /etc/pam.d/systemd-run0 ]]; the
|
||||
assert_eq "$(run0 -D / pwd)" "/"
|
||||
assert_eq "$(run0 --user=testuser pwd)" "/home/testuser"
|
||||
assert_eq "$(run0 -D / --user=testuser pwd)" "/"
|
||||
|
||||
# Verify that all combinations of --pty/--pipe come to the sam results
|
||||
assert_eq "$(run0 echo -n foo)" "foo"
|
||||
assert_eq "$(run0 --pty echo -n foo)" "foo"
|
||||
assert_eq "$(run0 --pipe echo -n foo)" "foo"
|
||||
assert_eq "$(run0 --pipe --pty echo -n foo)" "foo"
|
||||
|
||||
# Validate when we invoke run0 without a tty, that depending on --pty it either allocates a tty or not
|
||||
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'
|
||||
|
@ -39,6 +39,15 @@ assert_eq() {(
|
||||
fi
|
||||
)}
|
||||
|
||||
assert_neq() {(
|
||||
set +ex
|
||||
|
||||
if [[ "${1?}" = "${2?}" ]]; then
|
||||
echo "FAIL: not expected: '$2' actual: '$1'" >&2
|
||||
exit 1
|
||||
fi
|
||||
)}
|
||||
|
||||
assert_le() {(
|
||||
set +ex
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user