Files
DroidDeck/tools/linuxfs/preload/links.c
T
Kurt Himebauch fe71084f23 feat: replace the LXQt desktop with SteamOS-style KDE Plasma (#473)
* feat: replace the LXQt desktop with SteamOS-style KDE Plasma

* feat: leaving the KDE desktop logs out through Plasma and returns to gaming mode

* feat: DroidDeck logo wallpaper as the KDE desktop default

* feat: build the KDE wallpaper from the DroidDeck mark artwork

* ci: keep the built desktop package as a short-lived artifact for device testing

* fix: the desktop loading screen no longer promises Steam on the desktop

* docs: the output resize comments name the desktop's KWin

* fix: the desktop package verifies every package's Arch Linux ARM signature and never replaces a published tag

* fix: programs sent to the GPU from the desktop drop its software rendering overrides

* fix: an interrupted desktop install no longer counts as installed

* feat: pin the desktop package to its DroidDeck-Components release instead of the catalog
2026-10-09 10:39:50 -04:00

57 lines
2.7 KiB
C

/*
* Lock files taken by hard link, which Android denies apps.
*
* libICE and libXau lock an authority file the classic way: create "<file>-c", then link() it to
* "<file>-l" - the link either appears or fails because the other holder's is there. Android's
* SELinux policy refuses hard links in an app's data, so the link fails for everyone, the lock is
* never taken, and Plasma's session manager gives up at "Could not lock ICEAuthority file". With
* no session manager there is no Plasma desktop.
*
* Only that convention is answered here: when the real link is refused and the new name ends in
* "-l", a symlink stands in. Creating a symlink fails on an existing name just as a link does, so
* the lock excludes as before, and the holder removes both names when it is done. Every other
* link keeps the real answer: a program that links a file into place and then deletes the
* original would be left with a dangling symlink.
*/
#define _GNU_SOURCE
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
static int refused(int error) { return error == EPERM || error == EACCES; }
static int lock_name(const char *path) {
size_t n = path ? strlen(path) : 0;
return n > 2 && strcmp(path + n - 2, "-l") == 0;
}
/* The answer to link(oldpath, newpath), given the real call's: a refused lock link becomes a symlink. */
__attribute__((visibility("hidden"))) int bl_link_lock(const char *oldpath, const char *newpath, int result) {
/* libc's own symlink: dircache.c's wrapper may be holding its lock around this call. */
static int (*real_symlink)(const char *, const char *);
if (result == 0 || !refused(errno) || !lock_name(newpath)) return result;
if (real_symlink == NULL) real_symlink = dlsym(RTLD_NEXT, "symlink");
return real_symlink(oldpath, newpath);
}
/* 64-bit builds wrap link() in dircache.c, which hands its result to bl_link_lock. */
#if __SIZEOF_POINTER__ != 8
int link(const char *oldpath, const char *newpath) {
static int (*real_link)(const char *, const char *);
if (real_link == NULL) real_link = dlsym(RTLD_NEXT, "link");
return bl_link_lock(oldpath, newpath, real_link(oldpath, newpath));
}
#endif
int linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags) {
static int (*real_linkat)(int, const char *, int, const char *, int);
if (real_linkat == NULL) real_linkat = dlsym(RTLD_NEXT, "linkat");
int result = real_linkat(olddirfd, oldpath, newdirfd, newpath, flags);
/* A relative old name would resolve against the new name's directory as a symlink's target. */
if (result != 0 && refused(errno) && lock_name(newpath) && oldpath[0] == '/' && flags == 0)
return symlinkat(oldpath, newdirfd, newpath);
return result;
}