master ohmu/fastfetch-openbsd / src / detection / initsystem / initsystem_linux.c
ohmu  ·  2026-10-15
  1#include "initsystem.h"
  2#include "common/processing.h"
  3#include "common/binary.h"
  4#include "common/strutil.h"
  5
  6#include <libgen.h>
  7#include <unistd.h>
  8
  9[[maybe_unused]] static bool extractSystemdVersion(const char* str, uint32_t len, void* userdata) {
 10    if (!ffStrStartsWith(str, "systemd ")) {
 11        return true;
 12    }
 13    const char* pstart = str + strlen("systemd ");
 14    const char* pend = memmem(pstart, len - strlen("systemd "), " running in ", strlen(" running in "));
 15    if (!pend) {
 16        return true;
 17    }
 18    ffStrbufSetNS((FFstrbuf*) userdata, (uint32_t) (pend - pstart), pstart);
 19    return false;
 20}
 21
 22const char* ffDetectInitSystem(FFInitSystemResult* result) {
 23    const char* error = ffProcessGetBasicInfoLinux((int) result->pid, &result->name, nullptr, nullptr);
 24    if (error) {
 25#ifdef __ANDROID__
 26        if (access("/system/bin/init", F_OK) == 0) {
 27            ffStrbufSetStatic(&result->exe, "/system/bin/init");
 28            ffStrbufSetStatic(&result->name, "init");
 29            return nullptr;
 30        }
 31#endif
 32        return error;
 33    }
 34
 35    const char* _;
 36    // In linux /proc/1/exe is not readable
 37    ffProcessGetInfoLinux((int) result->pid, &result->name, &result->exe, &_, nullptr);
 38    if (result->exe.chars[0] == '/') {
 39        // In some old system, /sbin/init is a symlink
 40        char buf[PATH_MAX];
 41        if (realpath(result->exe.chars, buf)) {
 42            ffStrbufSetS(&result->exe, buf);
 43            ffStrbufSetS(&result->name, basename(result->exe.chars));
 44        }
 45    }
 46
 47    if (instance.config.general.detectVersion) {
 48#if (defined(__linux__) && !defined(__ANDROID__)) || defined(__GNU__)
 49        if (ffStrbufEqualS(&result->name, "systemd")) {
 50            ffBinaryExtractStrings(result->exe.chars, extractSystemdVersion, &result->version, (uint32_t) strlen("systemd 0.0 running in x"));
 51            if (result->version.length == 0) {
 52                if (ffProcessAppendStdOut(&result->version, (char* const[]) {
 53                                                                ffStrbufEndsWithS(&result->exe, "/systemd") ? result->exe.chars : "systemctl", // use exe path in case users have another systemd installed
 54                                                                "--version",
 55                                                                nullptr,
 56                                                            }) == nullptr &&
 57                    result->version.length) {
 58                    uint32_t iStart = ffStrbufFirstIndexC(&result->version, '(');
 59                    if (iStart < result->version.length) {
 60                        uint32_t iEnd = ffStrbufNextIndexC(&result->version, iStart + 1, ')');
 61                        ffStrbufSubstrBefore(&result->version, iEnd);
 62                        ffStrbufSubstrAfter(&result->version, iStart);
 63                    }
 64                }
 65            }
 66        } else if (ffStrbufEqualS(&result->name, "dinit")) {
 67            if (ffProcessAppendStdOut(&result->version, (char* const[]) {
 68                                                            ffStrbufEndsWithS(&result->exe, "/dinit") ? result->exe.chars : "dinit",
 69                                                            "--version",
 70                                                            nullptr,
 71                                                        }) == nullptr &&
 72                result->version.length) {
 73                // Dinit version 0.18.0.
 74                ffStrbufSubstrBeforeFirstC(&result->version, '\n');
 75                ffStrbufTrimRight(&result->version, '.');
 76                ffStrbufSubstrAfterLastC(&result->version, ' ');
 77            }
 78        } else if (ffStrbufEqualS(&result->name, "shepherd")) {
 79            if (ffProcessAppendStdOut(&result->version, (char* const[]) {
 80                                                            ffStrbufEndsWithS(&result->exe, "/shepherd") ? result->exe.chars : "shepherd",
 81                                                            "--version",
 82                                                            nullptr,
 83                                                        }) == nullptr &&
 84                result->version.length) {
 85                // shepherd (GNU Shepherd) 1.0.6
 86                // The first line in the output might not contain the version
 87                if (!ffStrbufStartsWithS(&result->version, "shepherd")) {
 88                    ffStrbufSubstrAfterFirstC(&result->version, '\n');
 89                }
 90
 91                ffStrbufSubstrBeforeFirstC(&result->version, '\n');
 92                ffStrbufSubstrAfterLastC(&result->version, ' ');
 93            }
 94        }
 95#elif __APPLE__
 96        if (ffStrbufEqualS(&result->name, "launchd")) {
 97            if (ffProcessAppendStdOut(&result->version, (char* const[]) {
 98                                                            "/bin/launchctl",
 99                                                            "version",
100                                                            nullptr,
101                                                        }) == nullptr &&
102                result->version.length) {
103                uint32_t iStart = ffStrbufFirstIndexS(&result->version, "Version ");
104                if (iStart < result->version.length) {
105                    iStart += (uint32_t) strlen("Version");
106                    uint32_t iEnd = ffStrbufNextIndexC(&result->version, iStart + 1, ':');
107                    ffStrbufSubstrBefore(&result->version, iEnd);
108                    ffStrbufSubstrAfter(&result->version, iStart);
109                }
110            }
111        }
112#endif
113    }
114
115    return nullptr;
116}