]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
util: add generic calls for prefixing a root directory to a path
authorLennart Poettering <lennart@poettering.net>
Wed, 13 May 2015 15:42:10 +0000 (17:42 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 13 May 2015 15:42:10 +0000 (17:42 +0200)
So far a number of utilities implemented their own calls for this, unify
them in prefix_root() and prefix_roota(). The former uses heap memory,
the latter allocates from the stack via alloca().

Port over most users of a --root= logic.

src/firstboot/firstboot.c
src/shared/conf-files.c
src/shared/path-util.c
src/shared/path-util.h
src/sysusers/sysusers.c
src/test/test-path-util.c
src/tmpfiles/tmpfiles.c

index 37326df0088ea6083fc4fcb48fbf2a1eecb89d2d..d156d57caf0a9dffda407d94e533e81312a5f49d 100644 (file)
@@ -52,8 +52,6 @@ static bool arg_copy_locale = false;
 static bool arg_copy_timezone = false;
 static bool arg_copy_root_password = false;
 
-#define prefix_roota(p) (arg_root ? (const char*) strjoina(arg_root, p) : (const char*) p)
-
 static void clear_string(char *x) {
 
         if (!x)
@@ -87,13 +85,13 @@ static void print_welcome(void) {
         if (done)
                 return;
 
-        os_release = prefix_roota("/etc/os-release");
+        os_release = prefix_roota(arg_root, "/etc/os-release");
         r = parse_env_file(os_release, NEWLINE,
                            "PRETTY_NAME", &pretty_name,
                            NULL);
         if (r == -ENOENT) {
 
-                os_release = prefix_roota("/usr/lib/os-release");
+                os_release = prefix_roota(arg_root, "/usr/lib/os-release");
                 r = parse_env_file(os_release, NEWLINE,
                                    "PRETTY_NAME", &pretty_name,
                                    NULL);
@@ -251,7 +249,7 @@ static int process_locale(void) {
         unsigned i = 0;
         int r;
 
-        etc_localeconf = prefix_roota("/etc/locale.conf");
+        etc_localeconf = prefix_roota(arg_root, "/etc/locale.conf");
         if (faccessat(AT_FDCWD, etc_localeconf, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
                 return 0;
 
@@ -325,7 +323,7 @@ static int process_timezone(void) {
         const char *etc_localtime, *e;
         int r;
 
-        etc_localtime = prefix_roota("/etc/localtime");
+        etc_localtime = prefix_roota(arg_root, "/etc/localtime");
         if (faccessat(AT_FDCWD, etc_localtime, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
                 return 0;
 
@@ -404,7 +402,7 @@ static int process_hostname(void) {
         const char *etc_hostname;
         int r;
 
-        etc_hostname = prefix_roota("/etc/hostname");
+        etc_hostname = prefix_roota(arg_root, "/etc/hostname");
         if (faccessat(AT_FDCWD, etc_hostname, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
                 return 0;
 
@@ -429,7 +427,7 @@ static int process_machine_id(void) {
         char id[SD_ID128_STRING_MAX];
         int r;
 
-        etc_machine_id = prefix_roota("/etc/machine-id");
+        etc_machine_id = prefix_roota(arg_root, "/etc/machine-id");
         if (faccessat(AT_FDCWD, etc_machine_id, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
                 return 0;
 
@@ -455,7 +453,7 @@ static int prompt_root_password(void) {
         if (!arg_prompt_root_password)
                 return 0;
 
-        etc_shadow = prefix_roota("/etc/shadow");
+        etc_shadow = prefix_roota(arg_root, "/etc/shadow");
         if (faccessat(AT_FDCWD, etc_shadow, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
                 return 0;
 
@@ -544,7 +542,7 @@ static int process_root_password(void) {
         const char *etc_shadow;
         int r;
 
-        etc_shadow = prefix_roota("/etc/shadow");
+        etc_shadow = prefix_roota(arg_root, "/etc/shadow");
         if (faccessat(AT_FDCWD, etc_shadow, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
                 return 0;
 
index 9ab08355e35cff0819462d4b2494d995643ff5d5..da8745b284d7462d9a3a03297b0784aff9bf09ce 100644 (file)
 
 static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) {
         _cleanup_closedir_ DIR *dir = NULL;
-        char *dirpath;
+        const char *dirpath;
+        int r;
 
         assert(path);
         assert(suffix);
 
-        dirpath = strjoina(root ? root : "", path);
+        dirpath = prefix_roota(root, path);
 
         dir = opendir(dirpath);
         if (!dir) {
@@ -53,7 +54,6 @@ static int files_add(Hashmap *h, const char *root, const char *path, const char
         for (;;) {
                 struct dirent *de;
                 char *p;
-                int r;
 
                 errno = 0;
                 de = readdir(dir);
index 635ce33b234a55a54d3ca4f5f10a9d3b08198669..7090989fcba21015b4638e49eeac894702a4b338 100644 (file)
@@ -793,3 +793,37 @@ int fsck_exists(const char *fstype) {
 
         return 0;
 }
+
+char *prefix_root(const char *root, const char *path) {
+        char *n, *p;
+        size_t l;
+
+        /* If root is passed, prefixes path with it. Otherwise returns
+         * it as is. */
+
+        assert(path);
+
+        /* First, drop duplicate prefixing slashes from the path */
+        while (path[0] == '/' && path[1] == '/')
+                path++;
+
+        if (isempty(root) || path_equal(root, "/"))
+                return strdup(path);
+
+        l = strlen(root) + 1 + strlen(path) + 1;
+
+        n = new(char, l);
+        if (!n)
+                return NULL;
+
+        p = stpcpy(n, root);
+
+        while (p > n && p[-1] == '/')
+                p--;
+
+        if (path[0] != '/')
+                *(p++) = '/';
+
+        strcpy(p, path);
+        return n;
+}
index 5548ce4a9410b33be21316e8c74071cd05141ec2..4f45cfd2b7ddf34778e4b8772c63cb517d205b02 100644 (file)
@@ -73,3 +73,30 @@ int fsck_exists(const char *fstype);
 /* Same as PATH_FOREACH_PREFIX but also includes the specified path itself */
 #define PATH_FOREACH_PREFIX_MORE(prefix, path) \
         for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/'))
+
+char *prefix_root(const char *root, const char *path);
+
+/* Similar to prefix_root(), but returns an alloca() buffer, or
+ * possibly a const pointer into the path parameter */
+#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) || path_equal(_root, "/"))           \
+                        _ret = _path;                                   \
+                else {                                                  \
+                        _l = strlen(_root) + 1 + strlen(_path) + 1;     \
+                        _n = alloca(_l);                                \
+                        _p = stpcpy(_n, _root);                         \
+                        while (_p > _n && _p[-1] == '/')                \
+                                _p--;                                   \
+                        if (_path[0] != '/')                            \
+                                *(_p++) = '/';                          \
+                        strcpy(_p, _path);                              \
+                        _ret = _n;                                      \
+                }                                                       \
+                _ret;                                                   \
+        })
index cc4c7ef53f499b0d8ac886bbebffcd5dc33431db..d7ba482834f8a6bf2c007cd45546662d11b85827 100644 (file)
@@ -80,15 +80,13 @@ static uid_t search_uid = UID_INVALID;
 static UidRange *uid_range = NULL;
 static unsigned n_uid_range = 0;
 
-#define fix_root(x) (arg_root ? strjoina(arg_root, x) : x)
-
 static int load_user_database(void) {
         _cleanup_fclose_ FILE *f = NULL;
         const char *passwd_path;
         struct passwd *pw;
         int r;
 
-        passwd_path = fix_root("/etc/passwd");
+        passwd_path = prefix_roota(arg_root, "/etc/passwd");
         f = fopen(passwd_path, "re");
         if (!f)
                 return errno == ENOENT ? 0 : -errno;
@@ -140,7 +138,7 @@ static int load_group_database(void) {
         struct group *gr;
         int r;
 
-        group_path = fix_root("/etc/group");
+        group_path = prefix_roota(arg_root, "/etc/group");
         f = fopen(group_path, "re");
         if (!f)
                 return errno == ENOENT ? 0 : -errno;
@@ -369,7 +367,7 @@ static int write_files(void) {
                 _cleanup_fclose_ FILE *original = NULL;
 
                 /* First we update the actual group list file */
-                group_path = fix_root("/etc/group");
+                group_path = prefix_roota(arg_root, "/etc/group");
                 r = fopen_temporary_label("/etc/group", group_path, &group, &group_tmp);
                 if (r < 0)
                         goto finish;
@@ -448,7 +446,7 @@ static int write_files(void) {
                 }
 
                 /* OK, now also update the shadow file for the group list */
-                gshadow_path = fix_root("/etc/gshadow");
+                gshadow_path = prefix_roota(arg_root, "/etc/gshadow");
                 r = fopen_temporary_label("/etc/gshadow", gshadow_path, &gshadow, &gshadow_tmp);
                 if (r < 0)
                         goto finish;
@@ -514,7 +512,7 @@ static int write_files(void) {
                 long lstchg;
 
                 /* First we update the user database itself */
-                passwd_path = fix_root("/etc/passwd");
+                passwd_path = prefix_roota(arg_root, "/etc/passwd");
                 r = fopen_temporary_label("/etc/passwd", passwd_path, &passwd, &passwd_tmp);
                 if (r < 0)
                         goto finish;
@@ -599,7 +597,7 @@ static int write_files(void) {
                 }
 
                 /* The we update the shadow database */
-                shadow_path = fix_root("/etc/shadow");
+                shadow_path = prefix_roota(arg_root, "/etc/shadow");
                 r = fopen_temporary_label("/etc/shadow", shadow_path, &shadow, &shadow_tmp);
                 if (r < 0)
                         goto finish;
@@ -802,7 +800,7 @@ static int uid_is_ok(uid_t uid, const char *name) {
 static int root_stat(const char *p, struct stat *st) {
         const char *fix;
 
-        fix = fix_root(p);
+        fix = prefix_roota(arg_root, p);
         if (stat(fix, st) < 0)
                 return -errno;
 
index e5b9c28bc0ea2e77407229e5e9d754177035e5e2..09f0f2f89edd165391021d00be911fcc6326457b 100644 (file)
@@ -294,6 +294,34 @@ static void test_path_startswith(void) {
         assert_se(!path_startswith("/foo/bar/barfoo/", "/f/b/b/"));
 }
 
+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 = prefix_root(r, p));
+        assert_se(streq_ptr(s, expected));
+
+        t = prefix_roota(r, p);
+        assert_se(t);
+        assert_se(streq_ptr(t, expected));
+}
+
+static void test_prefix_root(void) {
+        test_prefix_root_one("/", "/foo", "/foo");
+        test_prefix_root_one(NULL, "/foo", "/foo");
+        test_prefix_root_one("", "/foo", "/foo");
+        test_prefix_root_one("///", "/foo", "/foo");
+        test_prefix_root_one("/", "////foo", "/foo");
+        test_prefix_root_one(NULL, "////foo", "/foo");
+
+        test_prefix_root_one("/foo", "/bar", "/foo/bar");
+        test_prefix_root_one("/foo", "bar", "/foo/bar");
+        test_prefix_root_one("foo", "bar", "foo/bar");
+        test_prefix_root_one("/foo/", "/bar", "/foo/bar");
+        test_prefix_root_one("/foo/", "//bar", "/foo/bar");
+        test_prefix_root_one("/foo///", "//bar", "/foo/bar");
+}
+
 int main(int argc, char **argv) {
         test_path();
         test_find_binary(argv[0], true);
@@ -304,6 +332,7 @@ int main(int argc, char **argv) {
         test_make_relative();
         test_strv_resolve();
         test_path_startswith();
+        test_prefix_root();
 
         return 0;
 }
index 640ad4788da30152f97d8a583345e73e391c4aba..5a578350a3bc9b222d4e7d60f838e1efbac492ab 100644 (file)
@@ -1926,7 +1926,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         if (arg_root) {
                 char *p;
 
-                p = strappend(arg_root, i.path);
+                p = prefix_root(arg_root, i.path);
                 if (!p)
                         return log_oom();