1
0
mirror of https://github.com/systemd/systemd synced 2024-07-08 20:15:55 +00:00

Merge pull request #32603 from YHNdnzj/install-basename

shared/install: modernize and eliminate the use of basename()
This commit is contained in:
Yu Watanabe 2024-06-12 18:22:10 +09:00 committed by GitHub
commit 29d5da5fef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 302 additions and 281 deletions

View File

@ -699,7 +699,7 @@ static int add_names(
if (inst_fragment &&
fragment_basename &&
!streq(basename(inst_fragment), fragment_basename)) {
!path_equal_filename(inst_fragment, fragment_basename)) {
log_debug("Instance %s has fragment %s and is not an alias of %s.",
inst, inst_fragment, unit_name);
continue;

View File

@ -2187,9 +2187,8 @@ static int method_enqueue_marked_jobs(sd_bus_message *message, void *userdata, s
}
static int list_unit_files_by_patterns(sd_bus_message *message, void *userdata, sd_bus_error *error, char **states, char **patterns) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
Manager *m = ASSERT_PTR(userdata);
UnitFileList *item;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_hashmap_free_ Hashmap *h = NULL;
int r;
@ -2205,11 +2204,7 @@ static int list_unit_files_by_patterns(sd_bus_message *message, void *userdata,
if (r < 0)
return r;
h = hashmap_new(&unit_file_list_hash_ops_free);
if (!h)
return -ENOMEM;
r = unit_file_get_list(m->runtime_scope, NULL, h, states, patterns);
r = unit_file_get_list(m->runtime_scope, /* root_dir = */ NULL, states, patterns, &h);
if (r < 0)
return r;
@ -2217,8 +2212,8 @@ static int list_unit_files_by_patterns(sd_bus_message *message, void *userdata,
if (r < 0)
return r;
UnitFileList *item;
HASHMAP_FOREACH(item, h) {
r = sd_bus_message_append(reply, "(ss)", item->path, unit_file_state_to_string(item->state));
if (r < 0)
return r;
@ -2425,7 +2420,7 @@ static int reply_install_changes_and_free(
static int method_enable_unit_files_generic(
sd_bus_message *message,
Manager *m,
int (*call)(RuntimeScope scope, UnitFileFlags flags, const char *root_dir, char *files[], InstallChange **changes, size_t *n_changes),
int (*call)(RuntimeScope scope, UnitFileFlags flags, const char *root_dir, char * const *files, InstallChange **changes, size_t *n_changes),
bool carries_install_info,
sd_bus_error *error) {
@ -2490,7 +2485,7 @@ static int method_link_unit_files(sd_bus_message *message, void *userdata, sd_bu
return method_enable_unit_files_generic(message, userdata, unit_file_link, /* carries_install_info = */ false, error);
}
static int unit_file_preset_without_mode(RuntimeScope scope, UnitFileFlags flags, const char *root_dir, char **files, InstallChange **changes, size_t *n_changes) {
static int unit_file_preset_without_mode(RuntimeScope scope, UnitFileFlags flags, const char *root_dir, char * const *files, InstallChange **changes, size_t *n_changes) {
return unit_file_preset(scope, flags, root_dir, files, UNIT_FILE_PRESET_FULL, changes, n_changes);
}
@ -2550,7 +2545,7 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use
static int method_disable_unit_files_generic(
sd_bus_message *message,
Manager *m,
int (*call)(RuntimeScope scope, UnitFileFlags flags, const char *root_dir, char *files[], InstallChange **changes, size_t *n_changes),
int (*call)(RuntimeScope scope, UnitFileFlags flags, const char *root_dir, char * const *files, InstallChange **changes, size_t *n_changes),
bool carries_install_info,
sd_bus_error *error) {

View File

@ -596,7 +596,7 @@ static int normalize_portable_changes(
bool found = false;
for (size_t j = 0; j < n_changes_attached; ++j)
if (streq(basename(changes_detached[i].path), basename(changes_attached[j].path))) {
if (path_equal_filename(changes_detached[i].path, changes_attached[j].path)) {
found = true;
break;
}

View File

@ -23,39 +23,48 @@
#include "strv.h"
#include "unit-name.h"
int drop_in_file(const char *dir, const char *unit, unsigned level,
const char *name, char **ret_p, char **ret_q) {
int drop_in_file(
const char *dir,
const char *unit,
unsigned level,
const char *name,
char **ret_unit_dir,
char **ret_path) {
char prefix[DECIMAL_STR_MAX(unsigned) + 1] = {};
_cleanup_free_ char *b = NULL, *p = NULL, *q = NULL;
_cleanup_free_ char *n = NULL, *unit_dir = NULL, *path = NULL;
assert(dir);
assert(unit);
assert(name);
assert(ret_p);
assert(ret_q);
assert(ret_unit_dir);
assert(ret_path);
n = xescape(name, "/.");
if (!n)
return -ENOMEM;
if (!filename_is_valid(n))
return -EINVAL;
if (level != UINT_MAX)
xsprintf(prefix, "%u-", level);
b = xescape(name, "/.");
if (!b)
unit_dir = path_join(dir, strjoina(unit, ".d"));
path = strjoin(unit_dir, "/", prefix, n, ".conf");
if (!unit_dir || !path)
return -ENOMEM;
if (!filename_is_valid(b))
return -EINVAL;
p = strjoin(dir, "/", unit, ".d");
q = strjoin(p, "/", prefix, b, ".conf");
if (!p || !q)
return -ENOMEM;
*ret_p = TAKE_PTR(p);
*ret_q = TAKE_PTR(q);
*ret_unit_dir = TAKE_PTR(unit_dir);
*ret_path = TAKE_PTR(path);
return 0;
}
int write_drop_in(const char *dir, const char *unit, unsigned level,
const char *name, const char *data) {
int write_drop_in(
const char *dir,
const char *unit,
unsigned level,
const char *name,
const char *data) {
_cleanup_free_ char *p = NULL, *q = NULL;
int r;
@ -73,9 +82,14 @@ int write_drop_in(const char *dir, const char *unit, unsigned level,
return write_string_file_atomic_label(q, data);
}
int write_drop_in_format(const char *dir, const char *unit, unsigned level,
const char *name, const char *format, ...) {
_cleanup_free_ char *p = NULL;
int write_drop_in_format(
const char *dir,
const char *unit,
unsigned level,
const char *name,
const char *format, ...) {
_cleanup_free_ char *content = NULL;
va_list ap;
int r;
@ -85,13 +99,13 @@ int write_drop_in_format(const char *dir, const char *unit, unsigned level,
assert(format);
va_start(ap, format);
r = vasprintf(&p, format, ap);
r = vasprintf(&content, format, ap);
va_end(ap);
if (r < 0)
return -ENOMEM;
return write_drop_in(dir, unit, level, name, p);
return write_drop_in(dir, unit, level, name, content);
}
static int unit_file_add_dir(

View File

@ -6,14 +6,26 @@
#include "set.h"
#include "unit-name.h"
int drop_in_file(const char *dir, const char *unit, unsigned level,
const char *name, char **_p, char **_q);
int drop_in_file(
const char *dir,
const char *unit,
unsigned level,
const char *name,
char **ret_unit_dir,
char **ret_path);
int write_drop_in(const char *dir, const char *unit, unsigned level,
const char *name, const char *data);
int write_drop_in_format(const char *dir, const char *unit, unsigned level,
const char *name, const char *format, ...) _printf_(5, 6);
int write_drop_in(
const char *dir,
const char *unit,
unsigned level,
const char *name,
const char *data);
int write_drop_in_format(
const char *dir,
const char *unit,
unsigned level,
const char *name,
const char *format, ...) _printf_(5, 6);
int unit_file_find_dropin_paths(
const char *original_root,

View File

@ -117,17 +117,23 @@ static int in_search_path(const LookupPaths *lp, const char *path) {
/* Check if 'path' is in lp->search_path. */
r = path_extract_directory(ASSERT_PTR(path), &parent);
assert(lp);
assert(path);
r = path_extract_directory(path, &parent);
if (r < 0)
return r;
return path_strv_contains(ASSERT_PTR(lp)->search_path, parent);
return path_strv_contains(lp->search_path, parent);
}
static int underneath_search_path(const LookupPaths *lp, const char *path) {
static bool underneath_search_path(const LookupPaths *lp, const char *path) {
/* Check if 'path' is underneath lp->search_path. */
return !!path_startswith_strv(ASSERT_PTR(path), ASSERT_PTR(lp)->search_path);
assert(lp);
assert(path);
return path_startswith_strv(path, lp->search_path);
}
static const char* skip_root(const char *root_dir, const char *path) {
@ -660,7 +666,7 @@ static int remove_marked_symlinks_fd(
size_t *n_changes) {
_cleanup_closedir_ DIR *d = NULL;
int r = 0;
int r, ret = 0;
assert(remove_symlinks_to);
assert(fd >= 0);
@ -678,36 +684,32 @@ static int remove_marked_symlinks_fd(
rewinddir(d);
FOREACH_DIRENT(de, d, return -errno)
if (de->d_type == DT_DIR) {
_cleanup_close_ int nfd = -EBADF;
_cleanup_free_ char *p = NULL;
int nfd, q;
nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
nfd = RET_NERRNO(openat(fd, de->d_name, O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW));
if (nfd < 0) {
if (errno == ENOENT)
continue;
if (r == 0)
r = -errno;
if (nfd != -ENOENT)
RET_GATHER(ret, nfd);
continue;
}
p = path_make_absolute(de->d_name, path);
if (!p) {
safe_close(nfd);
if (!p)
return -ENOMEM;
}
/* This will close nfd, regardless whether it succeeds or not */
q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, lp, dry_run, restart, changes, n_changes);
if (q < 0 && r == 0)
r = q;
RET_GATHER(ret, remove_marked_symlinks_fd(remove_symlinks_to,
TAKE_FD(nfd), p,
config_path, lp,
dry_run,
restart,
changes, n_changes));
} else if (de->d_type == DT_LNK) {
_cleanup_free_ char *p = NULL;
bool found;
int q;
if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
continue;
@ -726,64 +728,61 @@ static int remove_marked_symlinks_fd(
if (!found) {
_cleanup_free_ char *template = NULL;
q = unit_name_template(de->d_name, &template);
if (q < 0 && q != -EINVAL)
return q;
if (q >= 0)
r = unit_name_template(de->d_name, &template);
if (r < 0 && r != -EINVAL)
return r;
if (r >= 0)
found = set_contains(remove_symlinks_to, template);
}
if (!found) {
_cleanup_free_ char *dest = NULL;
_cleanup_free_ char *dest = NULL, *dest_name = NULL;
q = chase(p, lp->root_dir, CHASE_NONEXISTENT, &dest, NULL);
if (q == -ENOENT)
r = chase(p, lp->root_dir, CHASE_NONEXISTENT, &dest, NULL);
if (r == -ENOENT)
continue;
if (q < 0) {
log_debug_errno(q, "Failed to resolve symlink \"%s\": %m", p);
install_changes_add(changes, n_changes, q, p, NULL);
if (r == 0)
r = q;
if (r < 0) {
log_debug_errno(r, "Failed to resolve symlink \"%s\": %m", p);
RET_GATHER(ret, install_changes_add(changes, n_changes, r, p, NULL));
continue;
}
r = path_extract_filename(dest, &dest_name);
if (r < 0)
return r;
found = set_contains(remove_symlinks_to, dest) ||
set_contains(remove_symlinks_to, basename(dest));
set_contains(remove_symlinks_to, dest_name);
}
if (!found)
continue;
if (!dry_run) {
if (unlinkat(fd, de->d_name, 0) < 0 && errno != ENOENT) {
if (r == 0)
r = -errno;
install_changes_add(changes, n_changes, -errno, p, NULL);
RET_GATHER(ret, install_changes_add(changes, n_changes, -errno, p, NULL));
continue;
}
(void) rmdir_parents(p, config_path);
}
q = install_changes_add(changes, n_changes, INSTALL_CHANGE_UNLINK, p, NULL);
if (q < 0)
return q;
r = install_changes_add(changes, n_changes, INSTALL_CHANGE_UNLINK, p, NULL);
if (r < 0)
return r;
/* Now, remember the full path (but with the root prefix removed) of
* the symlink we just removed, and remove any symlinks to it, too. */
const char *rp = skip_root(lp->root_dir, p);
q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: p);
if (q < 0)
return q;
if (q > 0 && !dry_run)
r = mark_symlink_for_removal(&remove_symlinks_to, rp ?: p);
if (r < 0)
return r;
if (r > 0 && !dry_run)
*restart = true;
}
return r;
return ret;
}
static int remove_marked_symlinks(
@ -809,7 +808,7 @@ static int remove_marked_symlinks(
return errno == ENOENT ? 0 : -errno;
do {
int q, cfd;
int cfd;
restart = false;
cfd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
@ -817,9 +816,12 @@ static int remove_marked_symlinks(
return -errno;
/* This takes possession of cfd and closes it */
q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, lp, dry_run, &restart, changes, n_changes);
if (r == 0)
r = q;
RET_GATHER(r, remove_marked_symlinks_fd(remove_symlinks_to,
cfd, config_path,
config_path, lp,
dry_run,
&restart,
changes, n_changes));
} while (restart);
return r;
@ -828,6 +830,9 @@ static int remove_marked_symlinks(
static int is_symlink_with_known_name(const InstallInfo *i, const char *name) {
int r;
assert(i);
assert(name);
if (streq(name, i->name))
return true;
@ -861,11 +866,17 @@ static int find_symlinks_in_directory(
const char *config_path,
bool *same_name_link) {
int r = 0;
int r, ret = 0;
assert(dir);
assert(dir_path);
assert(info);
assert(unit_name_is_valid(info->name, UNIT_NAME_ANY));
assert(config_path);
assert(same_name_link);
FOREACH_DIRENT(de, dir, return -errno) {
bool found_path = false, found_dest = false, b = false;
int q;
if (de->d_type != DT_LNK)
continue;
@ -874,32 +885,17 @@ static int find_symlinks_in_directory(
_cleanup_free_ char *dest = NULL;
/* Acquire symlink destination */
q = readlinkat_malloc(dirfd(dir), de->d_name, &dest);
if (q == -ENOENT)
r = readlinkat_malloc(dirfd(dir), de->d_name, &dest);
if (r < 0) {
if (r != -ENOENT)
RET_GATHER(ret, r);
continue;
if (q < 0) {
if (r == 0)
r = q;
continue;
}
/* Make absolute */
if (!path_is_absolute(dest)) {
char *x;
x = path_join(dir_path, dest);
if (!x)
return -ENOMEM;
free_and_replace(dest, x);
}
/* Check if what the symlink points to matches what we are looking for */
found_dest = streq(basename(dest), info->name);
found_dest = path_equal_filename(dest, info->name);
}
assert(unit_name_is_valid(info->name, UNIT_NAME_ANY));
/* Check if the symlink itself matches what we are looking for.
*
* If ignore_destination is specified, we only look at the source name.
@ -914,10 +910,10 @@ static int find_symlinks_in_directory(
if (!found_path && ignore_destination) {
_cleanup_free_ char *template = NULL;
q = unit_name_template(de->d_name, &template);
if (q < 0 && q != -EINVAL)
return q;
if (q >= 0)
r = unit_name_template(de->d_name, &template);
if (r < 0 && r != -EINVAL)
return r;
if (r >= 0)
found_dest = streq(template, info->name);
}
@ -927,7 +923,6 @@ static int find_symlinks_in_directory(
/* Filter out same name links in the main config path */
p = path_make_absolute(de->d_name, dir_path);
t = path_make_absolute(info->name, config_path);
if (!p || !t)
return -ENOMEM;
@ -941,15 +936,13 @@ static int find_symlinks_in_directory(
return 1;
/* Check if symlink name is in the set of names used by [Install] */
q = is_symlink_with_known_name(info, de->d_name);
if (q < 0)
return q;
if (q > 0)
return 1;
r = is_symlink_with_known_name(info, de->d_name);
if (r != 0)
return r;
}
}
return r;
return ret;
}
static int find_symlinks(
@ -961,7 +954,7 @@ static int find_symlinks(
bool *same_name_link) {
_cleanup_closedir_ DIR *config_dir = NULL;
int r = 0;
int r;
assert(i);
assert(config_path);
@ -1004,7 +997,7 @@ static int find_symlinks(
same_name_link);
if (r > 0)
return 1;
else if (r < 0)
if (r < 0)
log_debug_errno(r, "Failed to look up symlinks in \"%s\": %m", path);
}
@ -1187,16 +1180,19 @@ static int install_info_add(
bool auxiliary,
InstallInfo **ret) {
_cleanup_free_ char *name_alloc = NULL;
int r;
assert(ctx);
if (!name) {
/* 'name' and 'path' must not both be null. Check here 'path' using assert_se() to
* workaround a bug in gcc that generates a -Wnonnull warning when calling basename(),
* but this cannot be possible in any code path (See #6119). */
assert_se(path);
name = basename(path);
assert(path);
r = path_extract_filename(path, &name_alloc);
if (r < 0)
return r;
name = name_alloc;
}
if (!unit_name_is_valid(name, UNIT_NAME_ANY))
@ -1211,35 +1207,35 @@ static int install_info_add(
return 0;
}
_cleanup_(install_info_freep) InstallInfo *alloc = new(InstallInfo, 1);
if (!alloc)
_cleanup_(install_info_freep) InstallInfo *new_info = new(InstallInfo, 1);
if (!new_info)
return -ENOMEM;
*alloc = (InstallInfo) {
*new_info = (InstallInfo) {
.install_mode = _INSTALL_MODE_INVALID,
.auxiliary = auxiliary,
};
alloc->name = strdup(name);
if (!alloc->name)
return -ENOMEM;
if (root) {
alloc->root = strdup(root);
if (!alloc->root)
if (name_alloc)
new_info->name = TAKE_PTR(name_alloc);
else {
new_info->name = strdup(name);
if (!new_info->name)
return -ENOMEM;
}
if (path) {
alloc->path = strdup(path);
if (!alloc->path)
return -ENOMEM;
}
r = ordered_hashmap_ensure_put(&ctx->will_process, &string_hash_ops, alloc->name, alloc);
r = strdup_to(&new_info->root, root);
if (r < 0)
return r;
i = TAKE_PTR(alloc);
r = strdup_to(&new_info->path, path);
if (r < 0)
return r;
r = ordered_hashmap_ensure_put(&ctx->will_process, &string_hash_ops, new_info->name, new_info);
if (r < 0)
return r;
i = TAKE_PTR(new_info);
if (ret)
*ret = i;
@ -1662,7 +1658,7 @@ static int install_info_follow(
/* If the basename doesn't match, the caller should add a complete new entry for this. */
if (!ignore_different_name && !streq(basename(info->symlink_target), info->name))
if (!ignore_different_name && !path_equal_filename(info->symlink_target, info->name))
return -EXDEV;
free_and_replace(info->path, info->symlink_target);
@ -1686,9 +1682,9 @@ static int install_info_traverse(
unsigned k = 0;
int r;
assert(ctx);
assert(lp);
assert(start);
assert(ctx);
r = unit_file_search(ctx, start, lp, flags);
if (r < 0)
@ -1701,7 +1697,7 @@ static int install_info_traverse(
if (++k > UNIT_FILE_FOLLOW_SYMLINK_MAX)
return -ELOOP;
if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS)) {
if (!FLAGS_SET(flags, SEARCH_FOLLOW_CONFIG_SYMLINKS)) {
r = path_is_config(lp, i->path, true);
if (r < 0)
return r;
@ -1713,15 +1709,17 @@ static int install_info_traverse(
/* If linked, don't look at the target name */
/* ignore_different_name= */ i->install_mode == INSTALL_MODE_LINKED);
if (r == -EXDEV && i->symlink_target) {
_cleanup_free_ char *buffer = NULL;
_cleanup_free_ char *target_name = NULL, *unit_instance = NULL;
const char *bn;
/* Target is an alias, create a new install info object and continue with that. */
bn = basename(i->symlink_target);
r = path_extract_filename(i->symlink_target, &target_name);
if (r < 0)
return r;
if (unit_name_is_valid(i->name, UNIT_NAME_INSTANCE) &&
unit_name_is_valid(bn, UNIT_NAME_TEMPLATE)) {
unit_name_is_valid(target_name, UNIT_NAME_TEMPLATE)) {
_cleanup_free_ char *instance = NULL;
@ -1729,12 +1727,11 @@ static int install_info_traverse(
if (r < 0)
return r;
r = unit_name_replace_instance(bn, instance, &buffer);
r = unit_name_replace_instance(target_name, instance, &unit_instance);
if (r < 0)
return r;
if (streq(buffer, i->name)) {
if (streq(unit_instance, i->name)) {
/* We filled in the instance, and the target stayed the same? If so,
* then let's honour the link as it is. */
@ -1745,8 +1742,9 @@ static int install_info_traverse(
continue;
}
bn = buffer;
}
bn = unit_instance;
} else
bn = target_name;
r = install_info_add(ctx, bn, NULL, lp->root_dir, /* auxiliary= */ false, &i);
if (r < 0)
@ -1758,7 +1756,6 @@ static int install_info_traverse(
/* Translate error code to highlight this specific case */
return -ENOLINK;
}
if (r < 0)
return r;
}
@ -2310,7 +2307,7 @@ int unit_file_mask(
RuntimeScope scope,
UnitFileFlags flags,
const char *root_dir,
char **names,
char * const *names,
InstallChange **changes,
size_t *n_changes) {
@ -2353,7 +2350,7 @@ int unit_file_unmask(
RuntimeScope scope,
UnitFileFlags flags,
const char *root_dir,
char **names,
char * const *names,
InstallChange **changes,
size_t *n_changes) {
@ -2465,36 +2462,41 @@ int unit_file_link(
RuntimeScope scope,
UnitFileFlags flags,
const char *root_dir,
char **files,
char * const *files,
InstallChange **changes,
size_t *n_changes) {
_cleanup_(lookup_paths_done) LookupPaths lp = {};
_cleanup_strv_free_ char **todo = NULL;
_cleanup_ordered_hashmap_free_ OrderedHashmap *todo = NULL;
const char *config_path;
size_t n_todo = 0;
int r;
assert(scope >= 0);
assert(scope < _RUNTIME_SCOPE_MAX);
assert(changes);
assert(n_changes);
r = lookup_paths_init(&lp, scope, 0, root_dir);
if (r < 0)
return r;
config_path = (flags & UNIT_FILE_RUNTIME) ? lp.runtime_config : lp.persistent_config;
config_path = FLAGS_SET(flags, UNIT_FILE_RUNTIME) ? lp.runtime_config : lp.persistent_config;
if (!config_path)
return -ENXIO;
STRV_FOREACH(file, files) {
_cleanup_free_ char *full = NULL;
struct stat st;
char *fn;
_cleanup_free_ char *fn = NULL, *path = NULL, *full = NULL;
if (ordered_hashmap_contains(todo, *file))
continue;
if (!path_is_absolute(*file))
return install_changes_add(changes, n_changes, -EINVAL, *file, NULL);
fn = basename(*file);
r = path_extract_filename(*file, &fn);
if (r < 0)
return install_changes_add(changes, n_changes, r, *file, NULL);
if (!unit_name_is_valid(fn, UNIT_NAME_ANY))
return install_changes_add(changes, n_changes, -EUCLEAN, *file, NULL);
@ -2502,10 +2504,7 @@ int unit_file_link(
if (!full)
return -ENOMEM;
if (lstat(full, &st) < 0)
return install_changes_add(changes, n_changes, -errno, *file, NULL);
r = stat_verify_regular(&st);
r = verify_regular_at(AT_FDCWD, full, /* follow = */ false);
if (r < 0)
return install_changes_add(changes, n_changes, r, *file, NULL);
@ -2516,33 +2515,33 @@ int unit_file_link(
/* A silent noop if the file is already in the search path. */
continue;
r = underneath_search_path(&lp, *file);
if (r > 0)
r = -ETXTBSY;
if (underneath_search_path(&lp, *file))
return install_changes_add(changes, n_changes, -ETXTBSY, *file, NULL);
path = strdup(*file);
if (!path)
return -ENOMEM;
r = ordered_hashmap_ensure_put(&todo, &path_hash_ops_free_free, path, fn);
if (r < 0)
return install_changes_add(changes, n_changes, r, *file, NULL);
return r;
assert(r > 0);
if (!GREEDY_REALLOC0(todo, n_todo + 2))
return -ENOMEM;
todo[n_todo] = strdup(*file);
if (!todo[n_todo])
return -ENOMEM;
n_todo++;
TAKE_PTR(path);
TAKE_PTR(fn);
}
strv_uniq(todo);
r = 0;
STRV_FOREACH(i, todo) {
const char *fn, *path;
ORDERED_HASHMAP_FOREACH_KEY(fn, path, todo) {
_cleanup_free_ char *new_path = NULL;
new_path = path_make_absolute(basename(*i), config_path);
new_path = path_make_absolute(fn, config_path);
if (!new_path)
return -ENOMEM;
RET_GATHER(r, create_symlink(&lp, *i, new_path, flags & UNIT_FILE_FORCE, changes, n_changes));
RET_GATHER(r, create_symlink(&lp, path, new_path, FLAGS_SET(flags, UNIT_FILE_FORCE), changes, n_changes));
}
return r;
@ -2570,7 +2569,7 @@ static int path_shall_revert(const LookupPaths *lp, const char *path) {
int unit_file_revert(
RuntimeScope scope,
const char *root_dir,
char **names,
char * const *names,
InstallChange **changes,
size_t *n_changes) {
@ -2727,7 +2726,7 @@ int unit_file_add_dependency(
RuntimeScope scope,
UnitFileFlags file_flags,
const char *root_dir,
char **names,
char * const *names,
const char *target,
UnitDependency dep,
InstallChange **changes,
@ -2799,7 +2798,7 @@ static int do_unit_file_enable(
RuntimeScope scope,
UnitFileFlags flags,
const char *config_path,
char **names_or_paths,
char * const *names_or_paths,
InstallChange **changes,
size_t *n_changes) {
@ -2830,7 +2829,7 @@ int unit_file_enable(
RuntimeScope scope,
UnitFileFlags flags,
const char *root_dir,
char **names_or_paths,
char * const *names_or_paths,
InstallChange **changes,
size_t *n_changes) {
@ -2856,7 +2855,7 @@ static int do_unit_file_disable(
RuntimeScope scope,
UnitFileFlags flags,
const char *config_path,
char **names,
char * const *names,
InstallChange **changes,
size_t *n_changes) {
@ -2898,7 +2897,7 @@ int unit_file_disable(
RuntimeScope scope,
UnitFileFlags flags,
const char *root_dir,
char **files,
char * const *files,
InstallChange **changes,
size_t *n_changes) {
@ -2922,7 +2921,7 @@ int unit_file_disable(
static int normalize_linked_files(
RuntimeScope scope,
const LookupPaths *lp,
char **names_or_paths,
char * const *names_or_paths,
char ***ret_names,
char ***ret_files) {
@ -2981,7 +2980,7 @@ int unit_file_reenable(
RuntimeScope scope,
UnitFileFlags flags,
const char *root_dir,
char **names_or_paths,
char * const *names_or_paths,
InstallChange **changes,
size_t *n_changes) {
@ -3116,7 +3115,7 @@ int unit_file_lookup_state(
case INSTALL_MODE_REGULAR:
/* Check if the name we were querying is actually an alias */
if (!streq(name, basename(info->path)) && !unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
if (!path_equal_filename(name, info->path) && !unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
state = UNIT_FILE_ALIAS;
break;
}
@ -3399,6 +3398,8 @@ static int pattern_match_multiple_instances(
_cleanup_free_ char *templated_name = NULL;
int r;
assert(unit_name);
/* If no ret is needed or the rule itself does not have instances
* initialized, we return not matching */
if (!ret || !rule.instances)
@ -3445,20 +3446,25 @@ static int pattern_match_multiple_instances(
static int query_presets(const char *name, const UnitFilePresets *presets, char ***instance_name_list) {
PresetAction action = PRESET_UNKNOWN;
assert(name);
assert(presets);
if (!unit_name_is_valid(name, UNIT_NAME_ANY))
return -EINVAL;
for (size_t i = 0; i < presets->n_rules; i++)
if (pattern_match_multiple_instances(presets->rules[i], name, instance_name_list) > 0 ||
fnmatch(presets->rules[i].pattern, name, FNM_NOESCAPE) == 0) {
action = presets->rules[i].action;
FOREACH_ARRAY(i, presets->rules, presets->n_rules)
if (pattern_match_multiple_instances(*i, name, instance_name_list) > 0 ||
fnmatch(i->pattern, name, FNM_NOESCAPE) == 0) {
action = i->action;
break;
}
switch (action) {
case PRESET_UNKNOWN:
log_debug("Preset files don't specify rule for %s. Enabling.", name);
return PRESET_ENABLE;
case PRESET_ENABLE:
if (instance_name_list && *instance_name_list)
STRV_FOREACH(s, *instance_name_list)
@ -3466,12 +3472,15 @@ static int query_presets(const char *name, const UnitFilePresets *presets, char
else
log_debug("Preset files say enable %s.", name);
return PRESET_ENABLE;
case PRESET_DISABLE:
log_debug("Preset files say disable %s.", name);
return PRESET_DISABLE;
case PRESET_IGNORE:
log_debug("Preset files say ignore %s.", name);
return PRESET_IGNORE;
default:
assert_not_reached();
}
@ -3498,7 +3507,7 @@ static int execute_preset(
InstallContext *minus,
const LookupPaths *lp,
const char *config_path,
char **files,
char * const *files,
UnitFilePresetMode mode,
InstallChange **changes,
size_t *n_changes) {
@ -3597,7 +3606,7 @@ int unit_file_preset(
RuntimeScope scope,
UnitFileFlags file_flags,
const char *root_dir,
char **names,
char * const *names,
UnitFilePresetMode mode,
InstallChange **changes,
size_t *n_changes) {
@ -3716,27 +3725,24 @@ static UnitFileList* unit_file_list_free(UnitFileList *f) {
DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free);
DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
unit_file_list_hash_ops_free,
char,
string_hash_func,
string_compare_func,
UnitFileList,
unit_file_list_free);
DEFINE_PRIVATE_HASH_OPS_FULL(unit_file_list_hash_ops_free_free,
char, string_hash_func, string_compare_func, free,
UnitFileList, unit_file_list_free);
int unit_file_get_list(
RuntimeScope scope,
const char *root_dir,
Hashmap *h,
char **states,
char **patterns) {
char * const *states,
char * const *patterns,
Hashmap **ret) {
_cleanup_(lookup_paths_done) LookupPaths lp = {};
_cleanup_hashmap_free_ Hashmap *h = NULL;
int r;
assert(scope >= 0);
assert(scope < _RUNTIME_SCOPE_MAX);
assert(h);
assert(ret);
r = lookup_paths_init(&lp, scope, 0, root_dir);
if (r < 0)
@ -3758,7 +3764,11 @@ int unit_file_get_list(
}
FOREACH_DIRENT(de, d, return -errno) {
_cleanup_(unit_file_list_freep) UnitFileList *f = NULL;
if (!IN_SET(de->d_type, DT_LNK, DT_REG))
continue;
if (hashmap_contains(h, de->d_name))
continue;
if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
continue;
@ -3766,36 +3776,42 @@ int unit_file_get_list(
if (!strv_fnmatch_or_empty(patterns, de->d_name, FNM_NOESCAPE))
continue;
if (hashmap_get(h, de->d_name))
UnitFileState state;
r = unit_file_lookup_state(scope, &lp, de->d_name, &state);
if (r < 0)
state = UNIT_FILE_BAD;
if (!strv_isempty(states) &&
!strv_contains(states, unit_file_state_to_string(state)))
continue;
if (!IN_SET(de->d_type, DT_LNK, DT_REG))
continue;
f = new0(UnitFileList, 1);
_cleanup_(unit_file_list_freep) UnitFileList *f = new(UnitFileList, 1);
if (!f)
return -ENOMEM;
f->path = path_make_absolute(de->d_name, *dirname);
*f = (UnitFileList) {
.path = path_make_absolute(de->d_name, *dirname),
.state = state,
};
if (!f->path)
return -ENOMEM;
r = unit_file_lookup_state(scope, &lp, de->d_name, &f->state);
if (r < 0)
f->state = UNIT_FILE_BAD;
_cleanup_free_ char *unit_name = strdup(de->d_name);
if (!unit_name)
return -ENOMEM;
if (!strv_isempty(states) &&
!strv_contains(states, unit_file_state_to_string(f->state)))
continue;
r = hashmap_put(h, basename(f->path), f);
r = hashmap_ensure_put(&h, &unit_file_list_hash_ops_free_free, unit_name, f);
if (r < 0)
return r;
assert(r > 0);
f = NULL; /* prevent cleanup */
TAKE_PTR(unit_name);
TAKE_PTR(f);
}
}
*ret = TAKE_PTR(h);
return 0;
}

View File

@ -106,28 +106,28 @@ int unit_file_enable(
RuntimeScope scope,
UnitFileFlags flags,
const char *root_dir,
char **names_or_paths,
char * const *names_or_paths,
InstallChange **changes,
size_t *n_changes);
int unit_file_disable(
RuntimeScope scope,
UnitFileFlags flags,
const char *root_dir,
char **names,
char * const *names,
InstallChange **changes,
size_t *n_changes);
int unit_file_reenable(
RuntimeScope scope,
UnitFileFlags flags,
const char *root_dir,
char **names_or_paths,
char * const *names_or_paths,
InstallChange **changes,
size_t *n_changes);
int unit_file_preset(
RuntimeScope scope,
UnitFileFlags flags,
const char *root_dir,
char **names,
char * const *names,
UnitFilePresetMode mode,
InstallChange **changes,
size_t *n_changes);
@ -142,27 +142,27 @@ int unit_file_mask(
RuntimeScope scope,
UnitFileFlags flags,
const char *root_dir,
char **names,
char * const *names,
InstallChange **changes,
size_t *n_changes);
int unit_file_unmask(
RuntimeScope scope,
UnitFileFlags flags,
const char *root_dir,
char **names,
char * const *names,
InstallChange **changes,
size_t *n_changes);
int unit_file_link(
RuntimeScope scope,
UnitFileFlags flags,
const char *root_dir,
char **files,
char * const *files,
InstallChange **changes,
size_t *n_changes);
int unit_file_revert(
RuntimeScope scope,
const char *root_dir,
char **names,
char * const *names,
InstallChange **changes,
size_t *n_changes);
int unit_file_set_default(
@ -180,7 +180,7 @@ int unit_file_add_dependency(
RuntimeScope scope,
UnitFileFlags flags,
const char *root_dir,
char **names,
char * const *names,
const char *target,
UnitDependency dep,
InstallChange **changes,
@ -199,9 +199,7 @@ static inline int unit_file_exists(RuntimeScope scope, const LookupPaths *paths,
return unit_file_exists_full(scope, paths, name, NULL);
}
int unit_file_get_list(RuntimeScope scope, const char *root_dir, Hashmap *h, char **states, char **patterns);
extern const struct hash_ops unit_file_list_hash_ops_free;
int unit_file_get_list(RuntimeScope scope, const char *root_dir, char * const *states, char * const *patterns, Hashmap **ret);
InstallChangeType install_changes_add(InstallChange **changes, size_t *n_changes, InstallChangeType type, const char *path, const char *source);
void install_changes_free(InstallChange *changes, size_t n_changes);

View File

@ -142,23 +142,15 @@ static int output_unit_file_list(const UnitFileList *units, unsigned c) {
int verb_list_unit_files(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_free_ UnitFileList *units = NULL;
_cleanup_hashmap_free_ Hashmap *h = NULL;
_cleanup_free_ UnitFileList *units = NULL;
unsigned c = 0;
const char *state;
char *path;
int r;
bool fallback = false;
if (install_client_side()) {
UnitFileList *u;
unsigned n_units;
h = hashmap_new(&unit_file_list_hash_ops_free);
if (!h)
return log_oom();
r = unit_file_get_list(arg_runtime_scope, arg_root, h, arg_states, strv_skip(argv, 1));
r = unit_file_get_list(arg_runtime_scope, arg_root, arg_states, strv_skip(argv, 1), &h);
if (r < 0)
return log_error_errno(r, "Failed to get unit file list: %m");
@ -168,6 +160,7 @@ int verb_list_unit_files(int argc, char *argv[], void *userdata) {
if (!units)
return log_oom();
UnitFileList *u;
HASHMAP_FOREACH(u, h) {
if (!output_show_unit_file(u, NULL, NULL))
continue;
@ -179,6 +172,8 @@ int verb_list_unit_files(int argc, char *argv[], void *userdata) {
} else {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
const char *path, *state;
bool fallback = false;
sd_bus *bus;
r = acquire_bus(BUS_MANAGER, &bus);
@ -201,19 +196,17 @@ int verb_list_unit_files(int argc, char *argv[], void *userdata) {
return log_error_errno(r, "Failed to append unit dependencies: %m");
r = sd_bus_message_append_strv(m, names_with_deps);
if (r < 0)
return bus_log_create_error(r);
} else {
} else
r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
if (r < 0)
return bus_log_create_error(r);
}
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
/* Fallback to legacy ListUnitFiles method */
log_debug_errno(r, "Unable to list unit files through ListUnitFilesByPatterns, falling back to ListUnitsFiles method.");
fallback = true;
log_debug_errno(r, "Failed to list unit files: %s Falling back to ListUnitsFiles method.", bus_error_message(&error, r));
m = sd_bus_message_unref(m);
sd_bus_error_free(&error);
@ -235,16 +228,15 @@ int verb_list_unit_files(int argc, char *argv[], void *userdata) {
if (!GREEDY_REALLOC(units, c + 1))
return log_oom();
units[c] = (struct UnitFileList) {
path,
unit_file_state_from_string(state)
units[c] = (UnitFileList) {
.path = (char*) path,
.state = unit_file_state_from_string(state),
};
if (output_show_unit_file(&units[c],
fallback ? arg_states : NULL,
fallback ? strv_skip(argv, 1) : NULL))
c++;
}
if (r < 0)
return bus_log_parse_error(r);

View File

@ -680,8 +680,7 @@ TEST(preset_and_list) {
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM, root, "preset-ignore.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(h = hashmap_new(&unit_file_list_hash_ops_free));
assert_se(unit_file_get_list(RUNTIME_SCOPE_SYSTEM, root, h, NULL, NULL) >= 0);
ASSERT_OK(unit_file_get_list(RUNTIME_SCOPE_SYSTEM, root, NULL, NULL, &h));
p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service");
q = strjoina(root, "/usr/lib/systemd/system/preset-no.service");

View File

@ -31,9 +31,7 @@ int main(int argc, char* argv[]) {
test_setup_logging(LOG_DEBUG);
h = hashmap_new(&unit_file_list_hash_ops_free);
r = unit_file_get_list(RUNTIME_SCOPE_SYSTEM, NULL, h, NULL, NULL);
assert_se(r == 0);
ASSERT_OK(unit_file_get_list(RUNTIME_SCOPE_SYSTEM, NULL, NULL, NULL, &h));
HASHMAP_FOREACH(p, h) {
UnitFileState s = _UNIT_FILE_STATE_INVALID;

View File

@ -42,15 +42,12 @@ STATIC_DESTRUCTOR_REGISTER(runtime_dir, rm_rf_physical_and_freep);
/* For testing type compatibility. */
_unused_ ConfigPerfItemLookup unused_lookup = load_fragment_gperf_lookup;
TEST_RET(unit_file_get_set) {
TEST_RET(unit_file_get_list) {
int r;
_cleanup_hashmap_free_ Hashmap *h = NULL;
UnitFileList *p;
h = hashmap_new(&unit_file_list_hash_ops_free);
assert_se(h);
r = unit_file_get_list(RUNTIME_SCOPE_SYSTEM, NULL, h, NULL, NULL);
r = unit_file_get_list(RUNTIME_SCOPE_SYSTEM, NULL, NULL, NULL, &h);
if (IN_SET(r, -EPERM, -EACCES))
return log_tests_skipped_errno(r, "unit_file_get_list");