mirror of
https://github.com/systemd/systemd.git
synced 2025-01-28 21:47:38 +03:00
util: add generic calls for prefixing a root directory to a path
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.
This commit is contained in:
parent
8b44a3d22c
commit
1d13f648d0
@ -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;
|
||||
|
||||
|
@ -36,12 +36,13 @@
|
||||
|
||||
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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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; \
|
||||
})
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user