Newer
Older
/*
* 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 *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->ubuntu12_32 = g_build_filename (f->steam_install, "ubuntu12_32", NULL);
f->runtime = g_build_filename (f->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)
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
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);
g_file_make_symbolic_link (symlink_gfile, f->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);
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
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_root);
g_free (dot_steam_steam);
g_free (local_share);
g_free (ld_path);
g_free (prepended_path);
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)
{
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->ubuntu12_32);
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);