From 604e35319d8ddbb5f888032b27a29ae2b39414cd Mon Sep 17 00:00:00 2001 From: Ludovico de Nittis <ludovico.denittis@collabora.com> Date: Tue, 23 Mar 2021 15:21:52 +0100 Subject: [PATCH] wrap: Use a tmpfs home as a fallback when unsharing the home dir If we don't want to share the host home directory we expect to have either --home, --freedesktop-app-id, --steam-app-id or $SteamAppId. There are cases where this might not happen. For example if Steam has been launched with the PRESSURE_VESSEL_SHARE_HOME=0 env variable and we try to run "Help->System Information", the variable $SteamAppId will not be set and the container creation will fail. To avoid this issue we can use a tmpfs for the home directory when we are in batch mode. In this way the tmpfs will not be used if we need to run an actual game, because we want to retain the home directory on exit. Fixes: #66 Signed-off-by: Ludovico de Nittis <ludovico.denittis@collabora.com> --- pressure-vessel/wrap.c | 98 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 87 insertions(+), 11 deletions(-) diff --git a/pressure-vessel/wrap.c b/pressure-vessel/wrap.c index 21c5f6876..0f6be0e66 100644 --- a/pressure-vessel/wrap.c +++ b/pressure-vessel/wrap.c @@ -412,10 +412,63 @@ static const char * const steam_api_subdirs[] = static gboolean expose_steam (FlatpakExports *exports, FlatpakFilesystemMode mode, + gboolean is_home_shared, const char *real_home, const char *fake_home, GError **error); +static gboolean +use_tmpfs_home (FlatpakExports *exports, + FlatpakBwrap *bwrap, + PvEnviron *container_env, + GError **error) +{ + const gchar *home = g_get_home_dir (); + g_autofree char *real_home = realpath (home, NULL); + g_autofree gchar *cache = g_build_filename (real_home, ".cache", NULL); + g_autofree gchar *cache2 = g_build_filename (real_home, "cache", NULL); + g_autofree gchar *tmp = g_build_filename (cache, "tmp", NULL); + g_autofree gchar *config = g_build_filename (real_home, ".config", NULL); + g_autofree gchar *config2 = g_build_filename (real_home, "config", NULL); + g_autofree gchar *local = g_build_filename (real_home, ".local", NULL); + g_autofree gchar *data = g_build_filename (local, "share", NULL); + g_autofree gchar *data2 = g_build_filename (real_home, "data", NULL); + + g_return_val_if_fail (bwrap != NULL, FALSE); + g_return_val_if_fail (exports != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* If the logical path to the home dir has a symlink among its ancestors + * (e.g. /home/user when /home -> var/home exists), make sure the + * symlink structure gets mirrored in the container */ + flatpak_exports_add_path_dir (exports, home); + + /* Mount the tmpfs home directory onto the physical path to real_home, + * so that it will not conflict with symlinks created by the exports. + * See also https://github.com/flatpak/flatpak/issues/1278 and + * Flatpak commit f1df5cb1 */ + flatpak_bwrap_add_args (bwrap, "--tmpfs", real_home, NULL); + + flatpak_bwrap_add_args (bwrap, + "--dir", cache, + "--dir", tmp, + "--dir", config, + "--dir", local, + "--dir", data, + "--symlink", ".cache", cache2, + "--symlink", ".config", config2, + "--symlink", ".local/share", data2, + "--symlink", tmp, "/var/tmp", + NULL); + + pv_environ_lock_env (container_env, "XDG_CACHE_HOME", cache); + pv_environ_lock_env (container_env, "XDG_CONFIG_HOME", config); + pv_environ_lock_env (container_env, "XDG_DATA_HOME", data); + + return expose_steam (exports, FLATPAK_FILESYSTEM_MODE_READ_ONLY, FALSE, + real_home, NULL, error); +} + static gboolean use_fake_home (FlatpakExports *exports, FlatpakBwrap *bwrap, @@ -498,13 +551,14 @@ use_fake_home (FlatpakExports *exports, FLATPAK_FILESYSTEM_MODE_READ_WRITE, fake_home); - return expose_steam (exports, FLATPAK_FILESYSTEM_MODE_READ_ONLY, + return expose_steam (exports, FLATPAK_FILESYSTEM_MODE_READ_ONLY, FALSE, real_home, fake_home, error); } static gboolean expose_steam (FlatpakExports *exports, FlatpakFilesystemMode mode, + gboolean is_home_shared, const char *real_home, const char *fake_home, GError **error) @@ -520,7 +574,7 @@ expose_steam (FlatpakExports *exports, /* We need ~/.steam to be visible in the container, even if it's a * symlink to somewhere outside $HOME. (It's better not to do this; use * a separate Steam library instead, or use bind-mounts.) */ - if (fake_home != NULL) + if (!is_home_shared) { flatpak_exports_add_path_expose (exports, mode, dot_steam); } @@ -1300,6 +1354,7 @@ main (int argc, int original_argc = argc; gboolean is_flatpak_env = g_file_test ("/.flatpak-info", G_FILE_TEST_IS_REGULAR); gboolean is_main_program; + gboolean is_home_shared = TRUE; gboolean search_cwd = FALSE; g_autoptr(FlatpakBwrap) flatpak_subsandbox = NULL; g_autoptr(FlatpakBwrap) flatpak_run_on_host = NULL; @@ -1565,23 +1620,26 @@ main (int argc, if (opt_share_home == TRISTATE_YES) { - opt_fake_home = NULL; + is_home_shared = TRUE; } else if (opt_home) { + is_home_shared = FALSE; opt_fake_home = g_strdup (opt_home); } else if (opt_share_home == TRISTATE_MAYBE) { - opt_fake_home = NULL; + is_home_shared = TRUE; } else if (opt_freedesktop_app_id) { + is_home_shared = FALSE; opt_fake_home = g_build_filename (home, ".var", "app", opt_freedesktop_app_id, NULL); } else if (opt_steam_app_id) { + is_home_shared = FALSE; opt_freedesktop_app_id = g_strdup_printf ("com.steampowered.App%s", opt_steam_app_id); opt_fake_home = g_build_filename (home, ".var", "app", @@ -1589,6 +1647,7 @@ main (int argc, } else if (g_getenv ("STEAM_COMPAT_APP_ID") != NULL) { + is_home_shared = FALSE; opt_freedesktop_app_id = g_strdup_printf ("com.steampowered.App%s", g_getenv ("STEAM_COMPAT_APP_ID")); opt_fake_home = g_build_filename (home, ".var", "app", @@ -1596,11 +1655,19 @@ main (int argc, } else if (g_getenv ("SteamAppId") != NULL) { + is_home_shared = FALSE; opt_freedesktop_app_id = g_strdup_printf ("com.steampowered.App%s", g_getenv ("SteamAppId")); opt_fake_home = g_build_filename (home, ".var", "app", opt_freedesktop_app_id, NULL); } + else if (opt_batch) + { + is_home_shared = FALSE; + opt_fake_home = NULL; + g_info ("Unsharing the home directory without choosing a valid " + "candidate, using tmpfs as a fallback"); + } else { usage_error ("Either --home, --freedesktop-app-id, --steam-app-id " @@ -2057,7 +2124,7 @@ main (int argc, if (flatpak_subsandbox != NULL) { - if (opt_fake_home == NULL) + if (is_home_shared) { /* Nothing special to do here: we'll use the same home directory * and exports that the parent Flatpak sandbox used. */ @@ -2078,7 +2145,7 @@ main (int argc, g_assert (bwrap_filesystem_arguments != NULL); g_assert (exports != NULL); - if (opt_fake_home == NULL) + if (is_home_shared) { flatpak_exports_add_path_expose (exports, FLATPAK_FILESYSTEM_MODE_READ_WRITE, @@ -2094,17 +2161,26 @@ main (int argc, * should have a future "compat level" in which it's read-only, * like it already is when using a per-game home directory. */ if (!expose_steam (exports, FLATPAK_FILESYSTEM_MODE_READ_WRITE, - home, NULL, error)) + TRUE, home, NULL, error)) goto out; } else { bwrap_home_arguments = flatpak_bwrap_new (flatpak_bwrap_empty_env); - if (!use_fake_home (exports, bwrap_home_arguments, - container_env, opt_fake_home, - error)) - goto out; + if (opt_fake_home == NULL) + { + if (!use_tmpfs_home (exports, bwrap_home_arguments, + container_env, error)) + goto out; + } + else + { + if (!use_fake_home (exports, bwrap_home_arguments, + container_env, opt_fake_home, + error)) + goto out; + } } } -- GitLab