diff --git a/src/runtime.c b/src/runtime.c index cb719b13372e43b4fbb4a69f5d7a8f080ec0113e..c98cc017f409f8163a5a89317af0e44148bb5bac 100644 --- a/src/runtime.c +++ b/src/runtime.c @@ -61,6 +61,7 @@ struct _PvRuntime PvRuntimeFlags flags; gboolean any_libc_from_host; gboolean all_libc_from_host; + gboolean runtime_is_just_usr; }; struct _PvRuntimeClass @@ -337,9 +338,14 @@ pv_runtime_initable_init (GInitable *initable, self->runtime_usr = g_build_filename (self->source_files, "usr", NULL); - if (!g_file_test (self->runtime_usr, G_FILE_TEST_IS_DIR)) + if (g_file_test (self->runtime_usr, G_FILE_TEST_IS_DIR)) + { + self->runtime_is_just_usr = FALSE; + } + else { /* source_files is just a merged /usr. */ + self->runtime_is_just_usr = TRUE; g_free (self->runtime_usr); self->runtime_usr = g_strdup (self->source_files); } @@ -516,22 +522,65 @@ static gboolean pv_runtime_provide_container_access (PvRuntime *self, GError **error) { - /* TODO: Avoid using bwrap if we don't need to: when run from inside - * a Flatpak, it won't work. - * - * If we are working with a non-merged-/usr runtime, we can just - * set self->container_access to its path. - * - * Similarly, if we are working with a writeable copy of a runtime - * that we are editing in-place, we can set self->container_access to - * that. */ - - if (self->container_access_adverb == NULL) + if (self->container_access_adverb != NULL) + return TRUE; + + if (!self->runtime_is_just_usr) { - self->container_access = g_build_filename (self->tmpdir, "mnt", NULL); + static const char * const need_top_level[] = + { + "bin", + "etc", + "lib", + "sbin", + }; + gsize i; + + /* If we are working with a runtime that has a root directory containing + * /etc and /usr, we can just access it via its path - that's "the same + * shape" that the final system is going to be. + * + * In particular, if we are working with a writeable copy of a runtime + * that we are editing in-place, we can arrange that it's always + * like that. */ + g_debug ("%s: Setting up runtime without using bwrap", + G_STRFUNC); + self->container_access_adverb = flatpak_bwrap_new (NULL); + self->container_access = g_strdup (self->source_files); + + /* This is going to go poorly for us if the runtime is not complete. + * !self->runtime_is_just_usr means we know it has a /usr subdirectory, + * but that doesn't guarantee that it has /bin, /lib, /sbin (either + * in the form of real directories or symlinks into /usr) and /etc + * (for at least /etc/alternatives and /etc/ld.so.cache). + * + * This check is not intended to be exhaustive, merely something + * that will catch obvious mistakes like completely forgetting to + * add the merged-/usr symlinks. + * + * In practice we also need /lib64 for 64-bit-capable runtimes, + * but a pure 32-bit runtime would legitimately not have that, + * so we don't check for it. */ + for (i = 0; i < G_N_ELEMENTS (need_top_level); i++) + { + g_autofree gchar *path = g_build_filename (self->source_files, + need_top_level[i], + NULL); + if (!g_file_test (path, G_FILE_TEST_IS_DIR)) + g_warning ("%s does not exist, this probably won't work", + path); + } + } + else + { + /* Otherwise, will we need to use bwrap to build a directory hierarchy + * that is the same shape as the final system. */ + g_debug ("%s: Using bwrap to set up runtime that is just /usr", + G_STRFUNC); + + self->container_access = g_build_filename (self->tmpdir, "mnt", NULL); g_mkdir (self->container_access, 0700); - self->container_access = self->container_access; self->container_access_adverb = flatpak_bwrap_new (NULL); flatpak_bwrap_add_args (self->container_access_adverb,