tree-wide: Get rid of prefix_roota() in favor of path_join()

We deprecated prefix_roota() in favor of chase() and path_join().
Let's finish the removal by replacing the few remaining call sites
with path_join().
This commit is contained in:
Daan De Meyer
2025-05-05 12:05:15 +02:00
parent 38c9ca5380
commit 1fbfbe81b5
14 changed files with 136 additions and 93 deletions

3
TODO
View File

@@ -66,9 +66,6 @@ Janitorial Clean-ups:
* rework mount.c and swap.c to follow proper state enumeration/deserialization
semantics, like we do for device.c now
* get rid of prefix_roota() and similar, only use chase() and related
calls instead.
* get rid of basename() and replace by path_extract_filename()
* Replace our fstype_is_network() with a call to libmount's mnt_fstype_is_netfs()?

View File

@@ -154,32 +154,6 @@ int fsck_exists_for_fstype(const char *fstype);
_slash && ((*_slash = 0), true); \
_slash = strrchr((prefix), '/'))
/* Similar to path_join(), but only works for two components, and only the first one may be NULL and returns
* an alloca() buffer, or possibly a const pointer into the path parameter. */
/* DEPRECATED: use path_join() instead */
#define prefix_roota(root, path) \
({ \
const char* _path = (path), *_root = (root), *_ret; \
char *_p, *_n; \
size_t _l; \
while (_path[0] == '/' && _path[1] == '/') \
_path++; \
if (isempty(_root)) \
_ret = _path; \
else { \
_l = strlen(_root) + 1 + strlen(_path) + 1; \
_n = newa(char, _l); \
_p = stpcpy(_n, _root); \
while (_p > _n && _p[-1] == '/') \
_p--; \
if (_path[0] != '/') \
*(_p++) = '/'; \
strcpy(_p, _path); \
_ret = _n; \
} \
_ret; \
})
int path_find_first_component(const char **p, bool accept_dot_dot, const char **ret);
int path_find_last_component(const char *path, bool accept_dot_dot, const char **next, const char **ret);
const char* last_path_component(const char *path);

View File

@@ -1118,9 +1118,10 @@ static int remove_boot_efi(const char *esp_path) {
}
static int rmdir_one(const char *prefix, const char *suffix) {
const char *p;
_cleanup_free_ char *p = path_join(prefix, suffix);
if (!p)
return log_oom();
p = prefix_roota(prefix, suffix);
if (rmdir(p) < 0) {
bool ignore = IN_SET(errno, ENOENT, ENOTEMPTY);
@@ -1160,10 +1161,12 @@ static int remove_entry_directory(const char *root) {
}
static int remove_binaries(const char *esp_path) {
const char *p;
int r, q;
p = prefix_roota(esp_path, "/EFI/systemd");
_cleanup_free_ char *p = path_join(esp_path, "/EFI/systemd");
if (!p)
return log_oom();
r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
q = remove_boot_efi(esp_path);
@@ -1174,12 +1177,13 @@ static int remove_binaries(const char *esp_path) {
}
static int remove_file(const char *root, const char *file) {
const char *p;
assert(root);
assert(file);
p = prefix_roota(root, file);
_cleanup_free_ char *p = path_join(root, file);
if (!p)
return log_oom();
if (unlink(p) < 0) {
log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
"Failed to unlink file \"%s\": %m", p);

View File

@@ -123,7 +123,9 @@ static int context_save(Context *context) {
Link *link;
int r;
const char *p = prefix_roota(arg_root, NETWORK_UNIT_DIRECTORY);
_cleanup_free_ char *p = path_join(arg_root, NETWORK_UNIT_DIRECTORY);
if (!p)
return log_oom();
r = mkdir_p(p, 0755);
if (r < 0)

View File

@@ -1091,19 +1091,21 @@ static int setup_volatile_state(const char *directory) {
static int setup_volatile_state_after_remount_idmap(const char *directory, uid_t uid_shift, const char *selinux_apifs_context) {
_cleanup_free_ char *buf = NULL;
const char *p, *options;
int r;
assert(directory);
/* Then, after remount_idmap(), overmount /var/ with a tmpfs. */
p = prefix_roota(directory, "/var");
_cleanup_free_ char *p = path_join(directory, "/var");
if (!p)
return log_oom();
r = mkdir(p, 0755);
if (r < 0 && errno != EEXIST)
return log_error_errno(errno, "Failed to create %s: %m", directory);
options = "mode=0755" TMPFS_LIMITS_VOLATILE_STATE;
const char *options = "mode=0755" TMPFS_LIMITS_VOLATILE_STATE;
r = tmpfs_patch_options(options, uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &buf);
if (r < 0)
return log_oom();
@@ -1116,8 +1118,7 @@ static int setup_volatile_state_after_remount_idmap(const char *directory, uid_t
static int setup_volatile_yes(const char *directory, uid_t uid_shift, const char *selinux_apifs_context) {
bool tmpfs_mounted = false, bind_mounted = false;
_cleanup_(rmdir_and_freep) char *template = NULL;
_cleanup_free_ char *buf = NULL, *bindir = NULL;
const char *f, *t, *options;
_cleanup_free_ char *buf = NULL, *bindir = NULL, *f = NULL, *t = NULL;
struct stat st;
int r;
@@ -1148,7 +1149,7 @@ static int setup_volatile_yes(const char *directory, uid_t uid_shift, const char
if (r < 0)
return log_error_errno(r, "Failed to create temporary directory: %m");
options = "mode=0755" TMPFS_LIMITS_ROOTFS;
const char *options = "mode=0755" TMPFS_LIMITS_ROOTFS;
r = tmpfs_patch_options(options, uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &buf);
if (r < 0)
goto fail;
@@ -1161,8 +1162,17 @@ static int setup_volatile_yes(const char *directory, uid_t uid_shift, const char
tmpfs_mounted = true;
f = prefix_roota(directory, "/usr");
t = prefix_roota(template, "/usr");
f = path_join(directory, "/usr");
if (!f) {
r = log_oom();
goto fail;
}
t = path_join(template, "/usr");
if (!t) {
r = log_oom();
goto fail;
}
r = mkdir(t, 0755);
if (r < 0 && errno != EEXIST) {

View File

@@ -2260,7 +2260,6 @@ static int make_extra_nodes(const char *dest) {
static int setup_pts(const char *dest, uid_t chown_uid) {
_cleanup_free_ char *options = NULL;
const char *p;
int r;
#if HAVE_SELINUX
@@ -2279,7 +2278,10 @@ static int setup_pts(const char *dest, uid_t chown_uid) {
return log_oom();
/* Mount /dev/pts itself */
p = prefix_roota(dest, "/dev/pts");
_cleanup_free_ char *p = path_join(dest, "/dev/pts");
if (!p)
return log_oom();
r = RET_NERRNO(mkdir(p, 0755));
if (r < 0)
return log_error_errno(r, "Failed to create /dev/pts: %m");
@@ -2292,7 +2294,11 @@ static int setup_pts(const char *dest, uid_t chown_uid) {
return log_error_errno(r, "Failed to chown /dev/pts: %m");
/* Create /dev/ptmx symlink */
p = prefix_roota(dest, "/dev/ptmx");
free(p);
p = path_join(dest, "/dev/ptmx");
if (!p)
return log_oom();
if (symlink("pts/ptmx", p) < 0)
return log_error_errno(errno, "Failed to create /dev/ptmx symlink: %m");
r = userns_lchown(p, 0, 0);
@@ -2300,7 +2306,11 @@ static int setup_pts(const char *dest, uid_t chown_uid) {
return log_error_errno(r, "Failed to chown /dev/ptmx: %m");
/* And fix /dev/pts/ptmx ownership */
p = prefix_roota(dest, "/dev/pts/ptmx");
free(p);
p = path_join(dest, "/dev/pts/ptmx");
if (!p)
return log_oom();
r = userns_lchown(p, 0, 0);
if (r < 0)
return log_error_errno(r, "Failed to chown /dev/pts/ptmx: %m");
@@ -2384,7 +2394,6 @@ int make_run_host(const char *root) {
static int setup_credentials(const char *root) {
bool world_readable = false;
const char *q;
int r;
if (arg_credentials.n_credentials == 0)
@@ -2411,7 +2420,10 @@ static int setup_credentials(const char *root) {
if (r < 0)
return log_error_errno(r, "Failed to create /run/host/credentials: %m");
q = prefix_roota(root, "/run/host/credentials");
_cleanup_free_ char *q = path_join(root, "/run/host/credentials");
if (!q)
return log_oom();
r = mount_nofollow_verbose(LOG_ERR, NULL, q, "ramfs", MS_NOSUID|MS_NOEXEC|MS_NODEV, "mode=0700");
if (r < 0)
return r;
@@ -2527,7 +2539,6 @@ static int setup_hostname(void) {
static int setup_journal(const char *directory) {
_cleanup_free_ char *d = NULL;
const char *p, *q;
sd_id128_t this_id;
bool try;
int r;
@@ -2563,8 +2574,13 @@ static int setup_journal(const char *directory) {
}
}
p = strjoina("/var/log/journal/", SD_ID128_TO_STRING(arg_uuid));
q = prefix_roota(directory, p);
_cleanup_free_ char *p = path_join("/var/log/journal/", SD_ID128_TO_STRING(arg_uuid));
if (!p)
return log_oom();
_cleanup_free_ char *q = path_join(directory, p);
if (!q)
return log_oom();
if (path_is_mount_point(p) > 0) {
if (try)
@@ -2741,7 +2757,6 @@ static int reset_audit_loginuid(void) {
}
static int mount_tunnel_dig(const char *root) {
const char *p, *q;
int r;
if (arg_userns_mode == USER_NAMESPACE_MANAGED) {
@@ -2751,7 +2766,10 @@ static int mount_tunnel_dig(const char *root) {
(void) mkdir_p("/run/systemd/nspawn/", 0755);
(void) mkdir_p("/run/systemd/nspawn/propagate", 0600);
p = strjoina("/run/systemd/nspawn/propagate/", arg_machine);
_cleanup_free_ char *p = path_join("/run/systemd/nspawn/propagate/", arg_machine);
if (!p)
return log_oom();
(void) mkdir_p(p, 0600);
r = make_run_host(root);
@@ -2762,7 +2780,10 @@ static int mount_tunnel_dig(const char *root) {
if (r < 0)
return log_error_errno(r, "Failed to create "NSPAWN_MOUNT_TUNNEL": %m");
q = prefix_roota(root, NSPAWN_MOUNT_TUNNEL);
_cleanup_free_ char *q = path_join(root, NSPAWN_MOUNT_TUNNEL);
if (!q)
return log_oom();
r = mount_nofollow_verbose(LOG_ERR, p, q, NULL, MS_BIND, NULL);
if (r < 0)
return r;
@@ -3819,7 +3840,6 @@ static int outer_child(
_cleanup_(bind_user_context_freep) BindUserContext *bind_user_context = NULL;
_cleanup_strv_free_ char **os_release_pairs = NULL;
bool idmap = false;
const char *p;
pid_t pid;
ssize_t l;
int r;
@@ -4157,7 +4177,10 @@ static int outer_child(
(void) dev_setup(directory, chown_uid, chown_uid);
p = prefix_roota(directory, "/run/host");
_cleanup_free_ char *p = path_join(directory, "/run/host");
if (!p)
return log_oom();
(void) make_inaccessible_nodes(p, chown_uid, chown_uid);
r = setup_unix_export_host_inside(directory, unix_export_path);
@@ -4212,11 +4235,19 @@ static int outer_child(
return r;
/* The same stuff as the $container env var, but nicely readable for the entire payload */
p = prefix_roota(directory, "/run/host/container-manager");
free(p);
p = path_join(directory, "/run/host/container-manager");
if (!p)
return log_oom();
(void) write_string_file(p, arg_container_service_name, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MODE_0444);
/* The same stuff as the $container_uuid env var */
p = prefix_roota(directory, "/run/host/container-uuid");
free(p);
p = path_join(directory, "/run/host/container-uuid");
if (!p)
return log_oom();
(void) write_string_filef(p, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MODE_0444, SD_ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(arg_uuid));
if (!arg_use_cgns) {

View File

@@ -1782,9 +1782,9 @@ static int install_info_add_auto(
assert(name_or_path);
if (path_is_absolute(name_or_path)) {
const char *pp;
pp = prefix_roota(lp->root_dir, name_or_path);
_cleanup_free_ char *pp = path_join(lp->root_dir, name_or_path);
if (!pp)
return -ENOMEM;
return install_info_add(ctx, NULL, pp, lp->root_dir, /* auxiliary= */ false, ret);
} else

View File

@@ -458,11 +458,14 @@ static inline int run_test_table(void) {
#else
#define ASSERT_NOT_NULL(expr) \
({ \
if ((expr) == NULL) { \
typeof(expr) _result = (expr); \
if (_result == NULL) { \
log_error("%s:%i: Assertion failed: expected \"%s\" to be not NULL", \
PROJECT_FILE, __LINE__, #expr); \
abort(); \
} \
\
_result; \
})
#endif

View File

@@ -163,14 +163,15 @@ static int pin_choice(
struct stat st;
if (fstat(inode_fd, &st) < 0)
return log_debug_errno(errno, "Failed to stat discovered inode '%s': %m", prefix_roota(toplevel_path, inode_path));
return log_debug_errno(errno, "Failed to stat discovered inode '%s%s': %m",
empty_to_root(toplevel_path), skip_leading_slash(inode_path));
if (filter->type_mask != 0 &&
!BIT_SET(filter->type_mask, IFTODT(st.st_mode)))
return log_debug_errno(
SYNTHETIC_ERRNO(errno_from_mode(filter->type_mask, st.st_mode)),
"Inode '%s' has wrong type, found '%s'.",
prefix_roota(toplevel_path, inode_path),
"Inode '%s/%s' has wrong type, found '%s'.",
empty_to_root(toplevel_path), skip_leading_slash(inode_path),
inode_type_to_string(st.st_mode));
_cleanup_(pick_result_done) PickResult result = {
@@ -297,7 +298,8 @@ static int make_choice(
return 0;
}
if (r < 0)
return log_debug_errno(r, "Failed to open '%s': %m", prefix_roota(toplevel_path, p));
return log_debug_errno(r, "Failed to open '%s/%s': %m",
empty_to_root(toplevel_path), skip_leading_slash(p));
return pin_choice(
toplevel_path,
@@ -318,11 +320,13 @@ static int make_choice(
/* Convert O_PATH to a regular directory fd */
dir_fd = fd_reopen(inode_fd, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
if (dir_fd < 0)
return log_debug_errno(dir_fd, "Failed to reopen '%s' as directory: %m", prefix_roota(toplevel_path, inode_path));
return log_debug_errno(dir_fd, "Failed to reopen '%s/%s' as directory: %m",
empty_to_root(toplevel_path), skip_leading_slash(inode_path));
r = readdir_all(dir_fd, 0, &de);
if (r < 0)
return log_debug_errno(r, "Failed to read directory '%s': %m", prefix_roota(toplevel_path, inode_path));
return log_debug_errno(r, "Failed to read directory '%s/%s': %m",
empty_to_root(toplevel_path), skip_leading_slash(inode_path));
if (filter->architecture < 0) {
architectures = local_architectures;
@@ -466,7 +470,8 @@ static int make_choice(
object_fd = openat(dir_fd, best_filename, O_CLOEXEC|O_PATH);
if (object_fd < 0)
return log_debug_errno(errno, "Failed to open '%s': %m", prefix_roota(toplevel_path, p));
return log_debug_errno(errno, "Failed to open '%s/%s': %m",
empty_to_root(toplevel_path), skip_leading_slash(inode_path));
return pin_choice(
toplevel_path,

View File

@@ -944,11 +944,21 @@ static int write_files(Context *c) {
_cleanup_(unlink_and_freep) char *passwd_tmp = NULL, *group_tmp = NULL, *shadow_tmp = NULL, *gshadow_tmp = NULL;
int r;
const char
*passwd_path = prefix_roota(arg_root, "/etc/passwd"),
*shadow_path = prefix_roota(arg_root, "/etc/shadow"),
*group_path = prefix_roota(arg_root, "/etc/group"),
*gshadow_path = prefix_roota(arg_root, "/etc/gshadow");
_cleanup_free_ char *passwd_path = path_join(arg_root, "/etc/passwd");
if (!passwd_path)
return log_oom();
_cleanup_free_ char *shadow_path = path_join(arg_root, "/etc/shadow");
if (!shadow_path)
return log_oom();
_cleanup_free_ char *group_path = path_join(arg_root, "/etc/group");
if (!group_path)
return log_oom();
_cleanup_free_ char *gshadow_path = path_join(arg_root, "/etc/gshadow");
if (!gshadow_path)
return log_oom();
assert(c);

View File

@@ -54,10 +54,10 @@ TEST(cg_create) {
_cleanup_free_ char *here = NULL;
ASSERT_OK(cg_pid_get_path_shifted(0, NULL, &here));
const char *test_a = prefix_roota(here, "/test-a"),
*test_b = prefix_roota(here, "/test-b"),
*test_c = prefix_roota(here, "/test-b/test-c"),
*test_d = prefix_roota(here, "/test-b/test-d");
_cleanup_free_ char *test_a = ASSERT_NOT_NULL(path_join(here, "/test-a")),
*test_b = ASSERT_NOT_NULL(path_join(here, "/test-b")),
*test_c = ASSERT_NOT_NULL(path_join(here, "/test-b/test-c")),
*test_d = ASSERT_NOT_NULL(path_join(here, "/test-b/test-d"));
char *path;
log_info("Paths for test:\n%s\n%s", test_a, test_b);

View File

@@ -11,7 +11,7 @@
int main(int argc, char *argv[]) {
_cleanup_(rm_rf_physical_and_freep) char *p = NULL;
const char *f;
_cleanup_free_ char *f = NULL;
struct stat st;
test_setup_logging(LOG_DEBUG);
@@ -21,33 +21,38 @@ int main(int argc, char *argv[]) {
ASSERT_OK(mkdtemp_malloc("/tmp/test-dev-setupXXXXXX", &p));
f = prefix_roota(p, "/run/systemd");
f = ASSERT_NOT_NULL(path_join(p, "/run/systemd"));
ASSERT_OK(mkdir_p(f, 0755));
ASSERT_OK(make_inaccessible_nodes(f, 1, 1));
ASSERT_OK(make_inaccessible_nodes(f, 1, 1)); /* 2nd call should be a clean NOP */
f = prefix_roota(p, "/run/systemd/inaccessible/reg");
free(f);
f = ASSERT_NOT_NULL(path_join(p, "/run/systemd/inaccessible/reg"));
ASSERT_OK_ERRNO(stat(f, &st));
ASSERT_TRUE(S_ISREG(st.st_mode));
ASSERT_EQ(st.st_mode & 07777, 0000U);
f = prefix_roota(p, "/run/systemd/inaccessible/dir");
free(f);
f = ASSERT_NOT_NULL(path_join(p, "/run/systemd/inaccessible/dir"));
ASSERT_OK_ERRNO(stat(f, &st));
ASSERT_TRUE(S_ISDIR(st.st_mode));
ASSERT_EQ(st.st_mode & 07777, 0000U);
f = prefix_roota(p, "/run/systemd/inaccessible/fifo");
free(f);
f = ASSERT_NOT_NULL(path_join(p, "/run/systemd/inaccessible/fifo"));
ASSERT_OK_ERRNO(stat(f, &st));
ASSERT_TRUE(S_ISFIFO(st.st_mode));
ASSERT_EQ(st.st_mode & 07777, 0000U);
f = prefix_roota(p, "/run/systemd/inaccessible/sock");
free(f);
f = ASSERT_NOT_NULL(path_join(p, "/run/systemd/inaccessible/sock"));
ASSERT_OK_ERRNO(stat(f, &st));
ASSERT_TRUE(S_ISSOCK(st.st_mode));
ASSERT_EQ(st.st_mode & 07777, 0000U);
f = prefix_roota(p, "/run/systemd/inaccessible/chr");
free(f);
f = ASSERT_NOT_NULL(path_join(p, "/run/systemd/inaccessible/chr"));
if (stat(f, &st) < 0)
ASSERT_EQ(errno, ENOENT);
else {
@@ -55,7 +60,8 @@ int main(int argc, char *argv[]) {
ASSERT_EQ(st.st_mode & 07777, 0000U);
}
f = prefix_roota(p, "/run/systemd/inaccessible/blk");
free(f);
f = ASSERT_NOT_NULL(path_join(p, "/run/systemd/inaccessible/blk"));
if (stat(f, &st) < 0)
ASSERT_EQ(errno, ENOENT);
else {

View File

@@ -758,12 +758,11 @@ TEST(path_startswith) {
static void test_prefix_root_one(const char *r, const char *p, const char *expected) {
_cleanup_free_ char *s = NULL;
const char *t;
assert_se(s = path_join(r, p));
assert_se(path_equal(s, expected));
t = prefix_roota(r, p);
_cleanup_free_ char *t = path_join(r, p);
assert_se(t);
assert_se(path_equal(t, expected));
}

View File

@@ -2416,11 +2416,13 @@ static int create_symlink(Context *c, Item *i) {
r = chase(i->argument, arg_root, CHASE_SAFE|CHASE_PREFIX_ROOT|CHASE_NOFOLLOW, /* ret_path = */ NULL, /* ret_fd = */ NULL);
if (r == -ENOENT) {
/* Silently skip over lines where the source file is missing. */
log_info("Symlink source path '%s' does not exist, skipping line.", prefix_roota(arg_root, i->argument));
log_info("Symlink source path '%s/%s' does not exist, skipping line.",
empty_to_root(arg_root), skip_leading_slash(i->argument));
return 0;
}
if (r < 0)
return log_error_errno(r, "Failed to check if symlink source path '%s' exists: %m", prefix_roota(arg_root, i->argument));
return log_error_errno(r, "Failed to check if symlink source path '%s/%s' exists: %m",
empty_to_root(arg_root), skip_leading_slash(i->argument));
}
r = path_extract_filename(i->path, &bn);