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().
* 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()?
_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);
}
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);
}
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);
}
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);
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)
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();
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;
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;
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) {
static int setup_pts(const char *dest, uid_t chown_uid) {
_cleanup_free_ char *options = NULL;
- const char *p;
int r;
#if HAVE_SELINUX
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");
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);
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");
static int setup_credentials(const char *root) {
bool world_readable = false;
- const char *q;
int r;
if (arg_credentials.n_credentials == 0)
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;
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;
}
}
- 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)
}
static int mount_tunnel_dig(const char *root) {
- const char *p, *q;
int r;
if (arg_userns_mode == USER_NAMESPACE_MANAGED) {
(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);
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;
_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;
(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);
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) {
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
#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
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 = {
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,
/* 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;
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,
_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);
_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);
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);
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 {
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 {
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));
}
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);