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 && if (inst_fragment &&
fragment_basename && 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.", log_debug("Instance %s has fragment %s and is not an alias of %s.",
inst, inst_fragment, unit_name); inst, inst_fragment, unit_name);
continue; 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) { 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); Manager *m = ASSERT_PTR(userdata);
UnitFileList *item; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_hashmap_free_ Hashmap *h = NULL; _cleanup_hashmap_free_ Hashmap *h = NULL;
int r; int r;
@ -2205,11 +2204,7 @@ static int list_unit_files_by_patterns(sd_bus_message *message, void *userdata,
if (r < 0) if (r < 0)
return r; return r;
h = hashmap_new(&unit_file_list_hash_ops_free); r = unit_file_get_list(m->runtime_scope, /* root_dir = */ NULL, states, patterns, &h);
if (!h)
return -ENOMEM;
r = unit_file_get_list(m->runtime_scope, NULL, h, states, patterns);
if (r < 0) if (r < 0)
return r; return r;
@ -2217,8 +2212,8 @@ static int list_unit_files_by_patterns(sd_bus_message *message, void *userdata,
if (r < 0) if (r < 0)
return r; return r;
UnitFileList *item;
HASHMAP_FOREACH(item, h) { HASHMAP_FOREACH(item, h) {
r = sd_bus_message_append(reply, "(ss)", item->path, unit_file_state_to_string(item->state)); r = sd_bus_message_append(reply, "(ss)", item->path, unit_file_state_to_string(item->state));
if (r < 0) if (r < 0)
return r; return r;
@ -2425,7 +2420,7 @@ static int reply_install_changes_and_free(
static int method_enable_unit_files_generic( static int method_enable_unit_files_generic(
sd_bus_message *message, sd_bus_message *message,
Manager *m, 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, bool carries_install_info,
sd_bus_error *error) { 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); 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); 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( static int method_disable_unit_files_generic(
sd_bus_message *message, sd_bus_message *message,
Manager *m, 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, bool carries_install_info,
sd_bus_error *error) { sd_bus_error *error) {

View file

@ -596,7 +596,7 @@ static int normalize_portable_changes(
bool found = false; bool found = false;
for (size_t j = 0; j < n_changes_attached; ++j) 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; found = true;
break; break;
} }

View file

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

View file

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

View file

@ -106,28 +106,28 @@ int unit_file_enable(
RuntimeScope scope, RuntimeScope scope,
UnitFileFlags flags, UnitFileFlags flags,
const char *root_dir, const char *root_dir,
char **names_or_paths, char * const *names_or_paths,
InstallChange **changes, InstallChange **changes,
size_t *n_changes); size_t *n_changes);
int unit_file_disable( int unit_file_disable(
RuntimeScope scope, RuntimeScope scope,
UnitFileFlags flags, UnitFileFlags flags,
const char *root_dir, const char *root_dir,
char **names, char * const *names,
InstallChange **changes, InstallChange **changes,
size_t *n_changes); size_t *n_changes);
int unit_file_reenable( int unit_file_reenable(
RuntimeScope scope, RuntimeScope scope,
UnitFileFlags flags, UnitFileFlags flags,
const char *root_dir, const char *root_dir,
char **names_or_paths, char * const *names_or_paths,
InstallChange **changes, InstallChange **changes,
size_t *n_changes); size_t *n_changes);
int unit_file_preset( int unit_file_preset(
RuntimeScope scope, RuntimeScope scope,
UnitFileFlags flags, UnitFileFlags flags,
const char *root_dir, const char *root_dir,
char **names, char * const *names,
UnitFilePresetMode mode, UnitFilePresetMode mode,
InstallChange **changes, InstallChange **changes,
size_t *n_changes); size_t *n_changes);
@ -142,27 +142,27 @@ int unit_file_mask(
RuntimeScope scope, RuntimeScope scope,
UnitFileFlags flags, UnitFileFlags flags,
const char *root_dir, const char *root_dir,
char **names, char * const *names,
InstallChange **changes, InstallChange **changes,
size_t *n_changes); size_t *n_changes);
int unit_file_unmask( int unit_file_unmask(
RuntimeScope scope, RuntimeScope scope,
UnitFileFlags flags, UnitFileFlags flags,
const char *root_dir, const char *root_dir,
char **names, char * const *names,
InstallChange **changes, InstallChange **changes,
size_t *n_changes); size_t *n_changes);
int unit_file_link( int unit_file_link(
RuntimeScope scope, RuntimeScope scope,
UnitFileFlags flags, UnitFileFlags flags,
const char *root_dir, const char *root_dir,
char **files, char * const *files,
InstallChange **changes, InstallChange **changes,
size_t *n_changes); size_t *n_changes);
int unit_file_revert( int unit_file_revert(
RuntimeScope scope, RuntimeScope scope,
const char *root_dir, const char *root_dir,
char **names, char * const *names,
InstallChange **changes, InstallChange **changes,
size_t *n_changes); size_t *n_changes);
int unit_file_set_default( int unit_file_set_default(
@ -180,7 +180,7 @@ int unit_file_add_dependency(
RuntimeScope scope, RuntimeScope scope,
UnitFileFlags flags, UnitFileFlags flags,
const char *root_dir, const char *root_dir,
char **names, char * const *names,
const char *target, const char *target,
UnitDependency dep, UnitDependency dep,
InstallChange **changes, 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); 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); int unit_file_get_list(RuntimeScope scope, const char *root_dir, char * const *states, char * const *patterns, Hashmap **ret);
extern const struct hash_ops unit_file_list_hash_ops_free;
InstallChangeType install_changes_add(InstallChange **changes, size_t *n_changes, InstallChangeType type, const char *path, const char *source); 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); 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) { int verb_list_unit_files(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_free_ UnitFileList *units = NULL;
_cleanup_hashmap_free_ Hashmap *h = NULL; _cleanup_hashmap_free_ Hashmap *h = NULL;
_cleanup_free_ UnitFileList *units = NULL;
unsigned c = 0; unsigned c = 0;
const char *state;
char *path;
int r; int r;
bool fallback = false;
if (install_client_side()) { if (install_client_side()) {
UnitFileList *u;
unsigned n_units; unsigned n_units;
h = hashmap_new(&unit_file_list_hash_ops_free); r = unit_file_get_list(arg_runtime_scope, arg_root, arg_states, strv_skip(argv, 1), &h);
if (!h)
return log_oom();
r = unit_file_get_list(arg_runtime_scope, arg_root, h, arg_states, strv_skip(argv, 1));
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to get unit file list: %m"); 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) if (!units)
return log_oom(); return log_oom();
UnitFileList *u;
HASHMAP_FOREACH(u, h) { HASHMAP_FOREACH(u, h) {
if (!output_show_unit_file(u, NULL, NULL)) if (!output_show_unit_file(u, NULL, NULL))
continue; continue;
@ -179,6 +172,8 @@ int verb_list_unit_files(int argc, char *argv[], void *userdata) {
} else { } else {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
const char *path, *state;
bool fallback = false;
sd_bus *bus; sd_bus *bus;
r = acquire_bus(BUS_MANAGER, &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"); return log_error_errno(r, "Failed to append unit dependencies: %m");
r = sd_bus_message_append_strv(m, names_with_deps); r = sd_bus_message_append_strv(m, names_with_deps);
if (r < 0) } else
return bus_log_create_error(r);
} else {
r = sd_bus_message_append_strv(m, strv_skip(argv, 1)); r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
if (r < 0) if (r < 0)
return bus_log_create_error(r); return bus_log_create_error(r);
}
r = sd_bus_call(bus, m, 0, &error, &reply); r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) { if (r < 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
/* Fallback to legacy ListUnitFiles method */ /* Fallback to legacy ListUnitFiles method */
log_debug_errno(r, "Unable to list unit files through ListUnitFilesByPatterns, falling back to ListUnitsFiles method.");
fallback = true; 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); m = sd_bus_message_unref(m);
sd_bus_error_free(&error); 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)) if (!GREEDY_REALLOC(units, c + 1))
return log_oom(); return log_oom();
units[c] = (struct UnitFileList) { units[c] = (UnitFileList) {
path, .path = (char*) path,
unit_file_state_from_string(state) .state = unit_file_state_from_string(state),
}; };
if (output_show_unit_file(&units[c], if (output_show_unit_file(&units[c],
fallback ? arg_states : NULL, fallback ? arg_states : NULL,
fallback ? strv_skip(argv, 1) : NULL)) fallback ? strv_skip(argv, 1) : NULL))
c++; c++;
} }
if (r < 0) if (r < 0)
return bus_log_parse_error(r); 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-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(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_OK(unit_file_get_list(RUNTIME_SCOPE_SYSTEM, root, NULL, NULL, &h));
assert_se(unit_file_get_list(RUNTIME_SCOPE_SYSTEM, root, h, NULL, NULL) >= 0);
p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service"); p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service");
q = strjoina(root, "/usr/lib/systemd/system/preset-no.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); test_setup_logging(LOG_DEBUG);
h = hashmap_new(&unit_file_list_hash_ops_free); ASSERT_OK(unit_file_get_list(RUNTIME_SCOPE_SYSTEM, NULL, NULL, NULL, &h));
r = unit_file_get_list(RUNTIME_SCOPE_SYSTEM, NULL, h, NULL, NULL);
assert_se(r == 0);
HASHMAP_FOREACH(p, h) { HASHMAP_FOREACH(p, h) {
UnitFileState s = _UNIT_FILE_STATE_INVALID; 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. */ /* For testing type compatibility. */
_unused_ ConfigPerfItemLookup unused_lookup = load_fragment_gperf_lookup; _unused_ ConfigPerfItemLookup unused_lookup = load_fragment_gperf_lookup;
TEST_RET(unit_file_get_set) { TEST_RET(unit_file_get_list) {
int r; int r;
_cleanup_hashmap_free_ Hashmap *h = NULL; _cleanup_hashmap_free_ Hashmap *h = NULL;
UnitFileList *p; UnitFileList *p;
h = hashmap_new(&unit_file_list_hash_ops_free); r = unit_file_get_list(RUNTIME_SCOPE_SYSTEM, NULL, NULL, NULL, &h);
assert_se(h);
r = unit_file_get_list(RUNTIME_SCOPE_SYSTEM, NULL, h, NULL, NULL);
if (IN_SET(r, -EPERM, -EACCES)) if (IN_SET(r, -EPERM, -EACCES))
return log_tests_skipped_errno(r, "unit_file_get_list"); return log_tests_skipped_errno(r, "unit_file_get_list");