mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-11 02:51:10 +00:00
From Bannerlator's feat/linux-gamescope-runtime since this repo was cut: - Session teardown (4509d788): proot was SIGKILLed, which never lets its --kill-on-exit cleanup run; its tracees lived on with no tracer, every seccomp-trapped syscall failing with ENOSYS, spinning at a full core for over an hour. Now SIGTERM, a grace for proot's own cleanup, SIGKILL only if it will not go, then a sweep of the tree it had — snapshotted first, each pid checked against its start time. - The Steam client's controller interposer is its own source (fakeinput_steam.cpp, 28922e7c), separate from the one preloaded into Wine. - The seeder runs on a beat so a prefix the client creates mid-session is covered before its install scripts run (6ee86bff). - GE-Proton and proton-cachyos as compatibility tools: the registrar bannerlator-proton-extra and the compat script's adopt_extras (03867656). - space.c in the session shim: a library's own free space, not the phone's. The env-vs-args ordering bug (98d38931) does not apply here: nothing is added after the script name.
80 lines
3.6 KiB
C
80 lines
3.6 KiB
C
/*
|
|
* The free space a library reports.
|
|
*
|
|
* A library's games can live somewhere the folder that names the library does not. The card
|
|
* library is exactly that: its steamapps/common is bound to the card, but the directory above it
|
|
* belongs to the runtime image in the phone's own storage, and that directory is what the client
|
|
* measures. So it offers both install locations with the phone's free space against each, and the
|
|
* card's real figure - seventeen gigabytes more, on the device this was found on - never appears.
|
|
*
|
|
* The number is not only cosmetic: the client refuses an install it believes will not fit. Once
|
|
* the phone fills up it would turn down a card install with room to spare, and say nothing about
|
|
* why.
|
|
*
|
|
* Moving the whole library onto the card would fix the number and break something worse. The
|
|
* prefixes under steamapps/compatdata want symlinks and file locks, and the card is served over
|
|
* FUSE, which gives us neither - that is why they are kept in the runtime image in the first
|
|
* place. So the question is answered where the content actually is: a query about a library root
|
|
* named in BL_LIBRARY_SPACE is served from its steamapps/common, the bind that points at the
|
|
* card. Every other path is passed through untouched.
|
|
*/
|
|
#define _GNU_SOURCE
|
|
#include <dlfcn.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/statfs.h>
|
|
#include <sys/statvfs.h>
|
|
|
|
/* A library root, or its steamapps, resolved to the directory that holds the games. Returns the
|
|
* rewritten path in `buf`, or NULL when `path` is not one of ours and should be left alone. */
|
|
static const char *content_of(const char *path, char *buf, size_t len) {
|
|
const char *roots = getenv("BL_LIBRARY_SPACE");
|
|
if (!path || !roots || !*roots)
|
|
return NULL;
|
|
|
|
size_t path_len = strlen(path);
|
|
while (*roots) {
|
|
const char *end = strchr(roots, ':');
|
|
size_t root_len = end ? (size_t)(end - roots) : strlen(roots);
|
|
if (root_len > 0) {
|
|
/* The root itself, or the steamapps directly beneath it. Anything deeper is already inside
|
|
* a bind and answers for itself. */
|
|
int match = (path_len == root_len && !strncmp(path, roots, root_len)) ||
|
|
(path_len == root_len + 10 && !strncmp(path, roots, root_len) &&
|
|
!strcmp(path + root_len, "/steamapps"));
|
|
if (match) {
|
|
if (root_len + sizeof("/steamapps/common") > len)
|
|
return NULL;
|
|
memcpy(buf, roots, root_len);
|
|
strcpy(buf + root_len, "/steamapps/common");
|
|
return buf;
|
|
}
|
|
}
|
|
if (!end)
|
|
break;
|
|
roots = end + 1;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#define FORWARD(name, type) \
|
|
int name(const char *path, type *out) { \
|
|
static int (*real)(const char *, type *); \
|
|
char buf[4096]; \
|
|
const char *content; \
|
|
if (!real) \
|
|
real = dlsym(RTLD_NEXT, #name); \
|
|
if (!real) \
|
|
return -1; \
|
|
content = content_of(path, buf, sizeof(buf)); \
|
|
return real(content ? content : path, out); \
|
|
}
|
|
|
|
FORWARD(statfs, struct statfs)
|
|
FORWARD(statvfs, struct statvfs)
|
|
#ifdef __USE_LARGEFILE64
|
|
FORWARD(statfs64, struct statfs64)
|
|
FORWARD(statvfs64, struct statvfs64)
|
|
#endif
|