Skip to content
Snippets Groups Projects
Commit 6772f82a authored by Simon McVittie's avatar Simon McVittie
Browse files

exports: Update from flatpak PR 3830


This adds a mechanism to redirect from the host to a sysroot, intended
for unit testing, which we can (ab)use to redirect from the host to
/run/host.

Signed-off-by: default avatarSimon McVittie <smcv@collabora.com>
parent abcacf27
No related branches found
No related tags found
No related merge requests found
......@@ -62,5 +62,8 @@ FlatpakFilesystemMode flatpak_exports_path_get_mode (FlatpakExports *exports,
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FlatpakExports, flatpak_exports_free);
void flatpak_exports_take_host_fd (FlatpakExports *exports,
int fd);
#endif /* __FLATPAK_EXPORTS_H__ */
......@@ -110,8 +110,59 @@ struct _FlatpakExports
GHashTable *hash;
FlatpakFilesystemMode host_etc;
FlatpakFilesystemMode host_os;
int host_fd;
};
/*
* When populating /run/host, pretend @fd was the root of the host
* filesystem.
*/
void
flatpak_exports_take_host_fd (FlatpakExports *exports,
int fd)
{
glnx_close_fd (&exports->host_fd);
if (fd >= 0)
exports->host_fd = fd;
}
static gboolean
flatpak_exports_stat_in_host (FlatpakExports *exports,
const char *abs_path,
struct stat *buf,
int flags,
GError **error)
{
g_return_val_if_fail (abs_path[0] == '/', FALSE);
if (exports->host_fd >= 0)
{
/* If abs_path is "/usr", then stat "usr" relative to host_fd.
* As a special case, if abs_path is "/", stat host_fd itself,
* due to the use of AT_EMPTY_PATH. */
return glnx_fstatat (exports->host_fd, &abs_path[1], buf,
AT_EMPTY_PATH | flags,
error);
}
return glnx_fstatat (AT_FDCWD, abs_path, buf, flags, error);
}
static gchar *
flatpak_exports_readlink_in_host (FlatpakExports *exports,
const char *abs_path,
GError **error)
{
g_return_val_if_fail (abs_path[0] == '/', FALSE);
if (exports->host_fd >= 0)
return glnx_readlinkat_malloc (exports->host_fd, &abs_path[1],
NULL, error);
return glnx_readlinkat_malloc (AT_FDCWD, abs_path, NULL, error);
}
static void
exported_path_free (ExportedPath *exported_path)
{
......@@ -125,6 +176,7 @@ flatpak_exports_new (void)
FlatpakExports *exports = g_new0 (FlatpakExports, 1);
exports->hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GFreeFunc) exported_path_free);
exports->host_fd = -1;
return exports;
}
......@@ -250,15 +302,15 @@ path_is_symlink (const char *path)
typedef struct
{
const char *name;
GFileTest test;
int ifmt;
} LibsNeedEtc;
static const LibsNeedEtc libs_need_etc[] =
{
/* glibc */
{ "ld.so.cache", G_FILE_TEST_IS_REGULAR },
{ "ld.so.cache", S_IFREG },
/* Used for executables and a few libraries on e.g. Debian */
{ "alternatives", G_FILE_TEST_IS_DIR }
{ "alternatives", S_IFDIR }
};
void
......@@ -269,6 +321,7 @@ flatpak_exports_append_bwrap_args (FlatpakExports *exports,
g_autofree const char **keys = (const char **) g_hash_table_get_keys_as_array (exports->hash, &n_keys);
g_autoptr(GList) eps = NULL;
GList *l;
struct stat buf;
eps = g_hash_table_get_values (exports->hash);
eps = g_list_sort (eps, (GCompareFunc) compare_eps);
......@@ -332,7 +385,8 @@ flatpak_exports_append_bwrap_args (FlatpakExports *exports,
if (exports->host_os == FLATPAK_FILESYSTEM_MODE_READ_ONLY)
os_bind_mode = "--ro-bind";
if (g_file_test ("/usr", G_FILE_TEST_IS_DIR))
if (flatpak_exports_stat_in_host (exports, "/usr", &buf, 0, NULL) &&
S_ISDIR (buf.st_mode))
flatpak_bwrap_add_args (bwrap,
os_bind_mode, "/usr", "/run/host/usr", NULL);
......@@ -345,7 +399,7 @@ flatpak_exports_append_bwrap_args (FlatpakExports *exports,
g_assert (subdir[0] == '/');
/* e.g. /run/host/lib32 */
run_host_subdir = g_strconcat ("/run/host", subdir, NULL);
target = glnx_readlinkat_malloc (-1, subdir, NULL, NULL);
target = flatpak_exports_readlink_in_host (exports, subdir, NULL);
if (target != NULL &&
g_str_has_prefix (target, "usr/"))
......@@ -367,7 +421,8 @@ flatpak_exports_append_bwrap_args (FlatpakExports *exports,
"--symlink", target + 1, run_host_subdir,
NULL);
}
else if (g_file_test (subdir, G_FILE_TEST_IS_DIR))
else if (flatpak_exports_stat_in_host (exports, subdir, &buf, 0, NULL) &&
S_ISDIR (buf.st_mode))
{
/* e.g. /lib32 is a symlink to /opt/compat/ia32/lib,
* or is a plain directory because the host OS has not
......@@ -394,7 +449,9 @@ flatpak_exports_append_bwrap_args (FlatpakExports *exports,
const LibsNeedEtc *item = &libs_need_etc[i];
g_autofree gchar *host_path = g_strconcat ("/etc/", item->name, NULL);
if (g_file_test (host_path, item->test))
if (flatpak_exports_stat_in_host (exports, host_path,
&buf, 0, NULL) &&
(buf.st_mode & S_IFMT) == item->ifmt)
{
g_autofree gchar *run_host_path = g_strconcat ("/run/host/etc/", item->name, NULL);
......@@ -416,7 +473,8 @@ flatpak_exports_append_bwrap_args (FlatpakExports *exports,
if (exports->host_etc == FLATPAK_FILESYSTEM_MODE_READ_ONLY)
etc_bind_mode = "--ro-bind";
if (g_file_test ("/etc", G_FILE_TEST_IS_DIR))
if (flatpak_exports_stat_in_host (exports, "/etc", &buf, 0, NULL) &&
S_ISDIR (buf.st_mode))
flatpak_bwrap_add_args (bwrap,
etc_bind_mode, "/etc", "/run/host/etc", NULL);
}
......@@ -424,9 +482,9 @@ flatpak_exports_append_bwrap_args (FlatpakExports *exports,
/* As per the os-release specification https://www.freedesktop.org/software/systemd/man/os-release.html
* always read-only bind-mount /etc/os-release if it exists, or /usr/lib/os-release as a fallback from
* the host into the application's /run/host */
if (g_file_test ("/etc/os-release", G_FILE_TEST_EXISTS))
if (flatpak_exports_stat_in_host (exports, "/etc/os-release", &buf, 0, NULL))
flatpak_bwrap_add_args (bwrap, "--ro-bind", "/etc/os-release", "/run/host/os-release", NULL);
else if (g_file_test ("/usr/lib/os-release", G_FILE_TEST_EXISTS))
else if (flatpak_exports_stat_in_host (exports, "/usr/lib/os-release", &buf, 0, NULL))
flatpak_bwrap_add_args (bwrap, "--ro-bind", "/usr/lib/os-release", "/run/host/os-release", NULL);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment