/* * Copyright © 2019 Collabora Ltd. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "fake-home.h" #include <errno.h> #include <fcntl.h> #include <ftw.h> #include <gio/gio.h> #include <glib.h> #include <glib/gstdio.h> #include "test-utils.h" #include <steam-runtime-tools/steam-runtime-tools.h> /** * fake_home_new: * @home: (nullable) (type filename): Path to a temporary directory that will * be used, which must be in a trusted directory (not `/tmp` or `/var/tmp`). * If it doesn't exist yet, it will be created. If @home is %NULL a * random temporary directory will be used instead. * * Create a new #FakeHome object and a temporary folder in the file system * * Returns: the newely created #FakeHome object */ FakeHome * fake_home_new (const gchar *home) { GError *error = NULL; FakeHome *fake_home = g_slice_new (FakeHome); if (home) { gchar *dirname = g_path_get_dirname (home); g_assert_cmpstr (dirname, !=, "/tmp"); g_assert_cmpstr (dirname, !=, "/var/tmp"); fake_home->home = g_strdup (home); g_assert_cmpint (g_mkdir_with_parents (fake_home->home, 0755), ==, 0); g_free (dirname); } else { fake_home->home = g_dir_make_tmp ("fake-home-XXXXXX", &error); g_assert_no_error (error); } fake_home->create_pinning_libs = TRUE; fake_home->create_i386_folders = TRUE; fake_home->create_amd64_folders = TRUE; fake_home->create_root_symlink = TRUE; fake_home->create_steam_symlink = TRUE; fake_home->create_steamrt_files = TRUE; fake_home->add_environments = TRUE; fake_home->has_debian_bug_916303 = FALSE; fake_home->testing_beta_client = FALSE; fake_home->create_steam_mime_apps = TRUE; return fake_home; } /** * fake_home_create_structure: * @f: a #FakeHome object used to create the folder structure * * Create folders and files like a canonical Steam Installation. * As the home directory, the temporary folder stored in `home` is used. * A custom environ is also created and stored under `env`. * * Returns: %TRUE if the creation was successful */ gboolean fake_home_create_structure (FakeHome *f) { gboolean ret = FALSE; GFile *symlink_gfile = NULL; gchar *dot_steam = NULL; gchar *scripts = NULL; gchar *run = NULL; gchar *setup = NULL; gchar *version = NULL; gchar *dot_steam_bin32 = NULL; gchar *dot_steam_root = NULL; gchar *dot_steam_steam = NULL; gchar *local_share = NULL; gchar *ld_path = NULL; gchar *prepended_path = NULL; gchar *ubuntu12_32 = NULL; gchar *app_home = NULL; gchar *data_name = NULL; GError *error = NULL; int saved_errno; /* Instead of `/usr/bin/steam` we set Exec to `/usr/bin/env steam` because it * needs to point to something that we are sure to have */ const gchar *steam_data = "[Desktop Entry]\n" "Name=Steam\n" "Exec=/usr/bin/env steam %U\n" "Type=Application\n" "Actions=Library;\n" "MimeType=x-scheme-handler/steam;\n" "\n" "[Desktop Action Library]\n" "Name=Library\n" "Exec=steam steam://open/games"; const gchar *mime_list = "[Default Applications]\n" "x-scheme-handler/steam=steam.desktop;\n"; const gchar *mime_cache = "[MIME Cache]\n" "x-scheme-handler/steam=steam.desktop;\n"; g_return_val_if_fail (f != NULL, FALSE); dot_steam = g_build_filename (f->home, ".steam", NULL); if (f->has_debian_bug_916303) { f->steam_install = g_strdup (dot_steam); f->steam_data = g_build_filename (dot_steam, "steam", NULL); } else if (f->testing_beta_client) { f->steam_install = g_build_filename (f->home, "beta-client", NULL); f->steam_data = g_build_filename (f->home, ".local", "share", "Steam", NULL); } else { f->steam_install = g_build_filename (f->home, ".local", "share", "Steam", NULL); f->steam_data = g_strdup (f->steam_install); } f->runtime = g_build_filename (f->steam_install, "ubuntu12_32", "steam-runtime", NULL); scripts = g_build_filename (f->runtime, "scripts", NULL); if (g_mkdir_with_parents (dot_steam, 0755) != 0) goto out; if (g_mkdir_with_parents (f->steam_data, 0755) != 0) goto out; if (g_mkdir_with_parents (f->steam_install, 0755) != 0) goto out; if (g_mkdir_with_parents (scripts, 0755) != 0) goto out; f->pinned_32 = g_build_filename (f->runtime, "pinned_libs_32", NULL); f->pinned_64 = g_build_filename (f->runtime, "pinned_libs_64", NULL); f->i386_lib_i386 = g_build_filename (f->runtime, "i386", "lib", "i386-linux-gnu", NULL); f->i386_lib = g_build_filename (f->runtime, "i386", "lib", NULL); f->i386_usr_lib_i386 = g_build_filename (f->runtime, "i386", "usr", "lib", "i386-linux-gnu", NULL); f->i386_usr_lib = g_build_filename (f->runtime, "i386", "usr", "lib", NULL); f->i386_usr_bin = g_build_filename (f->runtime, "i386", "usr", "bin", NULL); f->amd64_lib_64 = g_build_filename (f->runtime, "amd64", "lib", "x86_64-linux-gnu", NULL); f->amd64_lib = g_build_filename (f->runtime, "amd64", "lib", NULL); f->amd64_usr_lib_64 = g_build_filename (f->runtime, "amd64", "usr", "lib", "x86_64-linux-gnu", NULL); f->amd64_usr_lib = g_build_filename (f->runtime, "amd64", "usr", "lib", NULL); f->amd64_bin = g_build_filename (f->runtime, "amd64", "bin", NULL); f->amd64_usr_bin = g_build_filename (f->runtime, "amd64", "usr", "bin", NULL); if (f->create_pinning_libs) { if (g_mkdir_with_parents (f->pinned_32, 0755) != 0) goto out; if (g_mkdir_with_parents (f->pinned_64, 0755) != 0) goto out; } if (f->create_i386_folders) { if (g_mkdir_with_parents (f->i386_lib_i386, 0755) != 0) goto out; if (g_mkdir_with_parents (f->i386_usr_lib_i386, 0755) != 0) goto out; if (g_mkdir_with_parents (f->i386_usr_bin, 0755) != 0) goto out; } if (f->create_amd64_folders) { if (g_mkdir_with_parents (f->amd64_lib_64, 0755) != 0) goto out; if (g_mkdir_with_parents (f->amd64_usr_lib_64, 0755) != 0) goto out; if (g_mkdir_with_parents (f->amd64_usr_bin, 0755) != 0) goto out; } if (f->create_steamrt_files) { run = g_build_filename (f->runtime, "run.sh", NULL); setup = g_build_filename (f->runtime, "setup.sh", NULL); version = g_build_filename (f->runtime, "version.txt", NULL); if (g_creat (run, 0755) < 0) goto out; if (g_creat (setup, 0755) < 0) goto out; if (g_creat (version, 0755) < 0) goto out; g_file_set_contents (version, "steam-runtime_0.20190711.3", -1, &error); g_assert_no_error (error); } if (f->has_debian_bug_916303) { dot_steam_steam = g_build_filename (dot_steam, "steam", NULL); if (g_mkdir_with_parents (dot_steam_steam, 0755) != 0) goto out; } if (f->create_root_symlink) { if (dot_steam_root == NULL) dot_steam_root = g_build_filename (dot_steam, "root", NULL); symlink_gfile = g_file_new_for_path (dot_steam_root); g_file_make_symbolic_link (symlink_gfile, f->steam_install, NULL, &error); g_object_unref (symlink_gfile); g_assert_no_error (error); dot_steam_bin32 = g_build_filename (dot_steam, "bin32", NULL); symlink_gfile = g_file_new_for_path (dot_steam_bin32); ubuntu12_32 = g_build_filename (f->steam_install, "ubuntu12_32", NULL); g_file_make_symbolic_link (symlink_gfile, ubuntu12_32, NULL, &error); g_object_unref (symlink_gfile); g_assert_no_error (error); } if (f->create_steam_symlink) { if (dot_steam_steam == NULL) dot_steam_steam = g_build_filename (dot_steam, "steam", NULL); symlink_gfile = g_file_new_for_path (dot_steam_steam); g_file_make_symbolic_link (symlink_gfile, f->steam_data, NULL, &error); g_object_unref (symlink_gfile); if (f->has_debian_bug_916303) { g_error_free (error); error = NULL; } else { g_assert_no_error (error); } } local_share = g_build_filename (f->home, ".local", "share", NULL); f->env = g_get_environ (); f->env = g_environ_setenv (f->env, "HOME", f->home, TRUE); f->env = g_environ_setenv (f->env, "XDG_DATA_HOME", local_share, TRUE); /* Make sure we don't find /etc/os-release or /usr/lib/os-release * if we happen to be in a Steam Runtime container */ f->sysroot = g_strdup (f->home); /* Make sure steam-runtime-system-info doesn't do that either */ f->env = g_environ_setenv (f->env, "SRT_TEST_SYSROOT", f->home, TRUE); if (f->add_environments) { const gchar *path; f->env = g_environ_setenv (f->env, "STEAM_RUNTIME", f->runtime, TRUE); ld_path = g_strjoin (":", f->pinned_32, f->pinned_64, f->i386_lib_i386, f->i386_lib, f->i386_usr_lib_i386, f->i386_usr_lib, f->amd64_lib_64, f->amd64_lib, f->amd64_usr_lib_64, f->amd64_usr_lib, NULL); f->env = g_environ_setenv (f->env, "LD_LIBRARY_PATH", ld_path, TRUE); path = g_environ_getenv (f->env, "PATH"); prepended_path = g_strjoin (":", f->amd64_bin, f->amd64_usr_bin, path, NULL); f->env = g_environ_setenv (f->env, "PATH", prepended_path, TRUE); } if (f->create_steam_mime_apps) { app_home = g_build_filename (local_share, "applications", NULL); if (g_mkdir_with_parents (app_home, 0755) != 0) goto out; /* Instead of `/usr/bin/steam` we set it to `/usr/bin/env`, like the "steam.desktop" * that we are going to create */ f->env = g_environ_setenv (f->env, "STEAMSCRIPT", "/usr/bin/env", TRUE); data_name = g_build_filename (app_home, "steam.desktop", NULL); g_file_set_contents (data_name, steam_data, -1, &error); g_assert_no_error (error); g_free (data_name); data_name = g_build_filename (app_home, "mimeapps.list", NULL); g_file_set_contents (data_name, mime_list, -1, &error); g_assert_no_error (error); g_free (data_name); data_name = g_build_filename (app_home, "mimeinfo.cache", NULL); g_file_set_contents (data_name, mime_cache, -1, &error); g_assert_no_error (error); } ret = TRUE; out: saved_errno = errno; g_free (dot_steam); g_free (scripts); g_free (run); g_free (setup); g_free (version); g_free (dot_steam_bin32); g_free (dot_steam_root); g_free (dot_steam_steam); g_free (local_share); g_free (ld_path); g_free (prepended_path); g_free (ubuntu12_32); g_free (app_home); g_free (data_name); if (!ret) g_warning ("Unable to create directories: %s", g_strerror (saved_errno)); return ret; } /** * fake_home_clean_up: * @f: the #FakeHome object to clean up and finalize * * Clean up a #FakeHome object recursively removing the created * home directory and freeing @f. */ void fake_home_clean_up (FakeHome *f) { if (!_srt_rm_rf (f->home)) g_debug ("Unable to remove the fake home directory: %s", f->home); g_free (f->home); g_free (f->steam_data); g_free (f->steam_install); g_free (f->runtime); g_free (f->pinned_32); g_free (f->pinned_64); g_free (f->i386_lib_i386); g_free (f->i386_lib); g_free (f->i386_usr_lib_i386); g_free (f->i386_usr_lib); g_free (f->i386_usr_bin); g_free (f->amd64_lib_64); g_free (f->amd64_lib); g_free (f->amd64_usr_lib_64); g_free (f->amd64_usr_lib); g_free (f->amd64_bin); g_free (f->amd64_usr_bin); g_free (f->sysroot); g_strfreev (f->env); g_slice_free (FakeHome, f); } /** * fake_home_apply_to_system_info: * @fake_home: The fake home directory * @info: The system info context * * Make @info look in @fake_home instead of the real root/home directories. */ void fake_home_apply_to_system_info (FakeHome *fake_home, SrtSystemInfo *info) { g_return_if_fail (fake_home != NULL); g_return_if_fail (fake_home->env != NULL); g_return_if_fail (fake_home->sysroot != NULL); g_return_if_fail (SRT_IS_SYSTEM_INFO (info)); srt_system_info_set_environ (info, fake_home->env); srt_system_info_set_sysroot (info, fake_home->sysroot); }