master ohmu/fastfetch-openbsd / src / common / android / package.c
ohmu  ·  2026-10-15
 1#include "common/android/package.h"
 2#include "common/android/api.h"
 3#include "common/debug.h"
 4#include "common/strutil.h"
 5
 6#include <string.h>
 7#include <unistd.h>
 8
 9// There is no way for a process to ask for its own package name: it is not in /proc/self/status, and
10// an app cannot list /data/data. The executable path carries it instead -- an app's binaries live
11// under /data/data/<package>/ or /data/user/<user>/<package>/, and /proc/self/exe resolves there.
12// Under Termux that is /data/data/com.termux/files/usr/bin/<binary>, whose third component is the
13// package.
14//
15// The memory cgroup carries the same information (4:memory:/apps/com.termux on the device this was
16// verified on), but the unified hierarchy spells it out as /apps/uid_10478/pid_26943 with no name
17// left in it, so the executable is the portable half of the two.
18bool ffAndroidGetOwnPackage(char* buffer, size_t capacity) {
19    char path[4096];
20    const ssize_t length = readlink("/proc/self/exe", path, sizeof(path) - 1);
21    if (length <= 0) {
22        FF_DEBUG("Cannot read /proc/self/exe, so the calling package cannot be derived");
23        return false;
24    }
25    path[length] = '\0';
26
27    const char* rest = nullptr;
28    const char* const dataPrefix = "/data/data/";
29    const char* const userPrefix = "/data/user/";
30    if (ffStrStartsWith(path, dataPrefix)) {
31        rest = path + strlen(dataPrefix);
32    } else if (ffStrStartsWith(path, userPrefix)) {
33        // /data/user/<user>/<package>/... -- the user number has to be stepped over before the
34        // package name starts, and only strchr() answers where that is.
35        rest = strchr(path + strlen(userPrefix), '/');
36        if (rest != nullptr) {
37            rest += 1;
38        }
39    }
40
41    if (rest == nullptr) {
42        const uint32_t uid = instance.state.platform.uid;
43        FF_DEBUG("The executable is not in an app data directory (\"%s\"), uid %u", path, uid);
44        if (uid != FF_ANDROID_PRIVILEGED_UID_SHELL) {
45            return false;
46        }
47        static const char shellPackage[] = FF_ANDROID_SHELL_PACKAGE;
48        if (sizeof(shellPackage) > capacity) {
49            return false;
50        }
51        memcpy(buffer, shellPackage, sizeof(shellPackage));
52        FF_DEBUG("The calling package is \"%s\" (the shell owns it)", buffer);
53        return true;
54    }
55
56    const char* end = strchr(rest, '/');
57    const size_t nameLength = end != nullptr ? (size_t) (end - rest) : strlen(rest);
58    if (nameLength == 0 || nameLength >= capacity) {
59        return false;
60    }
61    memcpy(buffer, rest, nameLength);
62    buffer[nameLength] = '\0';
63    FF_DEBUG("The calling package is \"%s\"", buffer);
64    return true;
65}