mirror of
https://github.com/systemd/systemd.git
synced 2025-03-19 22:50:17 +03:00
core: remove path to transient unit file from unit name maps on stop (#36186)
Fixes #35190.
This commit is contained in:
commit
869b0dfe6e
@ -1063,6 +1063,23 @@ int fputstrv(FILE *f, char * const *l, const char *separator, bool *space) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void string_strv_hashmap_remove(Hashmap *h, const char *key, const char *value) {
|
||||
assert(key);
|
||||
|
||||
if (value) {
|
||||
char **l = hashmap_get(h, key);
|
||||
if (!l)
|
||||
return;
|
||||
|
||||
strv_remove(l, value);
|
||||
if (!strv_isempty(l))
|
||||
return;
|
||||
}
|
||||
|
||||
_unused_ _cleanup_free_ char *key_free = NULL;
|
||||
strv_free(hashmap_remove2(h, key, (void**) &key_free));
|
||||
}
|
||||
|
||||
static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const char *value) {
|
||||
char **l;
|
||||
int r;
|
||||
|
@ -258,6 +258,10 @@ int fputstrv(FILE *f, char * const *l, const char *separator, bool *space);
|
||||
#define strv_free_and_replace(a, b) \
|
||||
free_and_replace_full(a, b, strv_free)
|
||||
|
||||
void string_strv_hashmap_remove(Hashmap *h, const char *key, const char *value);
|
||||
static inline void string_strv_ordered_hashmap_remove(OrderedHashmap *h, const char *key, const char *value) {
|
||||
string_strv_hashmap_remove(PLAIN_HASHMAP(h), key, value);
|
||||
}
|
||||
int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS);
|
||||
int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS);
|
||||
#define string_strv_hashmap_put(h, k, v) _string_strv_hashmap_put(h, k, v HASHMAP_DEBUG_SRC_ARGS)
|
||||
|
@ -646,13 +646,11 @@ static void unit_clear_dependencies(Unit *u) {
|
||||
|
||||
static void unit_remove_transient(Unit *u) {
|
||||
assert(u);
|
||||
assert(u->manager);
|
||||
|
||||
if (!u->transient)
|
||||
return;
|
||||
|
||||
if (u->fragment_path)
|
||||
(void) unlink(u->fragment_path);
|
||||
|
||||
STRV_FOREACH(i, u->dropin_paths) {
|
||||
_cleanup_free_ char *p = NULL, *pp = NULL;
|
||||
|
||||
@ -669,6 +667,17 @@ static void unit_remove_transient(Unit *u) {
|
||||
(void) unlink(*i);
|
||||
(void) rmdir(p);
|
||||
}
|
||||
|
||||
if (u->fragment_path) {
|
||||
(void) unlink(u->fragment_path);
|
||||
(void) unit_file_remove_from_name_map(
|
||||
&u->manager->lookup_paths,
|
||||
&u->manager->unit_cache_timestamp_hash,
|
||||
&u->manager->unit_id_map,
|
||||
&u->manager->unit_name_map,
|
||||
&u->manager->unit_path_cache,
|
||||
u->fragment_path);
|
||||
}
|
||||
}
|
||||
|
||||
static void unit_free_mounts_for(Unit *u) {
|
||||
|
@ -616,6 +616,41 @@ int unit_file_build_name_map(
|
||||
return 1;
|
||||
}
|
||||
|
||||
int unit_file_remove_from_name_map(
|
||||
const LookupPaths *lp,
|
||||
uint64_t *cache_timestamp_hash,
|
||||
Hashmap **unit_ids_map,
|
||||
Hashmap **unit_names_map,
|
||||
Set **path_cache,
|
||||
const char *path) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
|
||||
/* This assumes the specified path is already removed, and drops the relevant entries from the maps. */
|
||||
|
||||
/* If one of the lookup paths we are monitoring is already changed, let's rebuild the map. Then, the
|
||||
* new map should not contain entries relevant to the specified path. */
|
||||
r = unit_file_build_name_map(lp, cache_timestamp_hash, unit_ids_map, unit_names_map, path_cache);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
/* If not, drop the relevant entries. */
|
||||
|
||||
_cleanup_free_ char *name = NULL;
|
||||
r = path_extract_filename(path, &name);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to extract file name from '%s': %m", path);
|
||||
|
||||
_unused_ _cleanup_free_ char *key = NULL;
|
||||
free(hashmap_remove2(*unit_ids_map, name, (void**) &key));
|
||||
string_strv_hashmap_remove(*unit_names_map, name, name);
|
||||
free(set_remove(*path_cache, path));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_name(
|
||||
const char *unit_name,
|
||||
Set **names,
|
||||
|
@ -68,6 +68,14 @@ int unit_file_build_name_map(
|
||||
Hashmap **unit_names_map,
|
||||
Set **path_cache);
|
||||
|
||||
int unit_file_remove_from_name_map(
|
||||
const LookupPaths *lp,
|
||||
uint64_t *cache_timestamp_hash,
|
||||
Hashmap **unit_ids_map,
|
||||
Hashmap **unit_names_map,
|
||||
Set **path_cache,
|
||||
const char *path);
|
||||
|
||||
int unit_file_find_fragment(
|
||||
Hashmap *unit_ids_map,
|
||||
Hashmap *unit_name_map,
|
||||
|
@ -973,6 +973,22 @@ TEST(string_strv_hashmap) {
|
||||
|
||||
s = hashmap_get(m, "xxx");
|
||||
assert_se(strv_equal(s, STRV_MAKE("bar", "BAR")));
|
||||
|
||||
string_strv_hashmap_remove(m, "foo", "bar");
|
||||
ASSERT_NOT_NULL(s = hashmap_get(m, "foo"));
|
||||
ASSERT_TRUE(strv_equal(s, STRV_MAKE("BAR")));
|
||||
|
||||
string_strv_hashmap_remove(m, "foo", "BAR");
|
||||
ASSERT_NULL(hashmap_get(m, "foo"));
|
||||
|
||||
string_strv_hashmap_remove(m, "xxx", "BAR");
|
||||
ASSERT_NOT_NULL(s = hashmap_get(m, "xxx"));
|
||||
ASSERT_TRUE(strv_equal(s, STRV_MAKE("bar")));
|
||||
|
||||
string_strv_hashmap_remove(m, "xxx", "bar");
|
||||
ASSERT_NULL(hashmap_get(m, "xxx"));
|
||||
|
||||
ASSERT_TRUE(hashmap_isempty(m));
|
||||
}
|
||||
|
||||
TEST(hashmap_dump_sorted) {
|
||||
|
@ -1,11 +1,16 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "fileio.h"
|
||||
#include "initrd-util.h"
|
||||
#include "path-lookup.h"
|
||||
#include "path-util.h"
|
||||
#include "random-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "set.h"
|
||||
#include "special.h"
|
||||
#include "strv.h"
|
||||
#include "tests.h"
|
||||
#include "tmpfile-util.h"
|
||||
#include "unit-file.h"
|
||||
|
||||
TEST(unit_validate_alias_symlink_and_warn) {
|
||||
@ -86,6 +91,82 @@ TEST(unit_file_build_name_map) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool test_unit_file_remove_from_name_map_trail(const LookupPaths *lp, size_t trial) {
|
||||
int r;
|
||||
|
||||
log_debug("/* %s(trial=%zu) */", __func__, trial);
|
||||
|
||||
_cleanup_hashmap_free_ Hashmap *unit_ids = NULL, *unit_names = NULL;
|
||||
_cleanup_set_free_ Set *path_cache = NULL;
|
||||
ASSERT_OK_POSITIVE(unit_file_build_name_map(lp, NULL, &unit_ids, &unit_names, &path_cache));
|
||||
|
||||
_cleanup_free_ char *name = NULL;
|
||||
for (size_t i = 0; i < 100; i++) {
|
||||
ASSERT_OK(asprintf(&name, "test-unit-file-%"PRIx64".service", random_u64()));
|
||||
if (!hashmap_contains(unit_ids, name))
|
||||
break;
|
||||
name = mfree(name);
|
||||
}
|
||||
ASSERT_NOT_NULL(name);
|
||||
|
||||
_cleanup_free_ char *path = path_join(lp->transient, name);
|
||||
ASSERT_NOT_NULL(path);
|
||||
ASSERT_OK(write_string_file(path, "[Unit]\n", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755));
|
||||
|
||||
uint64_t cache_timestamp_hash = 0;
|
||||
ASSERT_OK_POSITIVE(unit_file_build_name_map(lp, &cache_timestamp_hash, &unit_ids, &unit_names, &path_cache));
|
||||
|
||||
ASSERT_STREQ(hashmap_get(unit_ids, name), path);
|
||||
ASSERT_TRUE(strv_equal(hashmap_get(unit_names, name), STRV_MAKE(name)));
|
||||
ASSERT_TRUE(set_contains(path_cache, path));
|
||||
|
||||
ASSERT_OK_ERRNO(unlink(path));
|
||||
|
||||
ASSERT_OK(r = unit_file_remove_from_name_map(lp, &cache_timestamp_hash, &unit_ids, &unit_names, &path_cache, path));
|
||||
if (r > 0)
|
||||
return false; /* someone touches unit files. Retrying. */
|
||||
|
||||
ASSERT_FALSE(hashmap_contains(unit_ids, name));
|
||||
ASSERT_FALSE(hashmap_contains(unit_names, path));
|
||||
ASSERT_FALSE(set_contains(path_cache, path));
|
||||
|
||||
_cleanup_hashmap_free_ Hashmap *unit_ids_2 = NULL, *unit_names_2 = NULL;
|
||||
_cleanup_set_free_ Set *path_cache_2 = NULL;
|
||||
ASSERT_OK_POSITIVE(unit_file_build_name_map(lp, NULL, &unit_ids_2, &unit_names_2, &path_cache_2));
|
||||
|
||||
if (hashmap_size(unit_ids) != hashmap_size(unit_ids_2) ||
|
||||
hashmap_size(unit_names) != hashmap_size(unit_names_2) ||
|
||||
!set_equal(path_cache, path_cache_2))
|
||||
return false;
|
||||
|
||||
const char *k, *v;
|
||||
HASHMAP_FOREACH_KEY(v, k, unit_ids)
|
||||
if (!streq_ptr(hashmap_get(unit_ids_2, k), v))
|
||||
return false;
|
||||
|
||||
char **l;
|
||||
HASHMAP_FOREACH_KEY(l, k, unit_names)
|
||||
if (!strv_equal_ignore_order(hashmap_get(unit_names_2, k), l))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
TEST(unit_file_remove_from_name_map) {
|
||||
_cleanup_(rm_rf_physical_and_freep) char *d = NULL;
|
||||
|
||||
_cleanup_(lookup_paths_done) LookupPaths lp = {};
|
||||
ASSERT_OK(lookup_paths_init(&lp, RUNTIME_SCOPE_SYSTEM, LOOKUP_PATHS_TEMPORARY_GENERATED, NULL));
|
||||
ASSERT_NOT_NULL(d = strdup(lp.temporary_dir));
|
||||
|
||||
for (size_t i = 0; i < 10; i++)
|
||||
if (test_unit_file_remove_from_name_map_trail(&lp, i))
|
||||
return;
|
||||
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
TEST(runlevel_to_target) {
|
||||
in_initrd_force(false);
|
||||
ASSERT_STREQ(runlevel_to_target(NULL), NULL);
|
||||
|
14
test/units/TEST-07-PID1.transient.sh
Executable file
14
test/units/TEST-07-PID1.transient.sh
Executable file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
set -ex
|
||||
set -o pipefail
|
||||
|
||||
journalctl --sync
|
||||
TS="$(date '+%H:%M:%S')"
|
||||
|
||||
systemd-run -u hogehoge.service sleep infinity
|
||||
systemctl daemon-reload
|
||||
systemctl stop hogehoge.service
|
||||
|
||||
journalctl --sync
|
||||
[[ -z "$(journalctl -b -q --since "$TS" -u hogehoge.service -p notice)" ]]
|
Loading…
x
Reference in New Issue
Block a user