summaryrefslogtreecommitdiffstats
path: root/src/detection/initsystem/initsystem_linux.c
diff options
context:
space:
mode:
authorsumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
committersumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
commit76424950e373d3b04ac3dd13019151bfba3e8423 (patch)
tree4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /src/detection/initsystem/initsystem_linux.c
Add the files
Diffstat (limited to 'src/detection/initsystem/initsystem_linux.c')
-rw-r--r--src/detection/initsystem/initsystem_linux.c116
1 files changed, 116 insertions, 0 deletions
diff --git a/src/detection/initsystem/initsystem_linux.c b/src/detection/initsystem/initsystem_linux.c
new file mode 100644
index 0000000..445657b
--- /dev/null
+++ b/src/detection/initsystem/initsystem_linux.c
@@ -0,0 +1,116 @@
+#include "initsystem.h"
+#include "common/processing.h"
+#include "common/binary.h"
+#include "common/strutil.h"
+
+#include <libgen.h>
+#include <unistd.h>
+
+FF_A_UNUSED static bool extractSystemdVersion(const char* str, uint32_t len, void* userdata) {
+ if (!ffStrStartsWith(str, "systemd ")) {
+ return true;
+ }
+ const char* pstart = str + strlen("systemd ");
+ const char* pend = memmem(pstart, len - strlen("systemd "), " running in ", strlen(" running in "));
+ if (!pend) {
+ return true;
+ }
+ ffStrbufSetNS((FFstrbuf*) userdata, (uint32_t) (pend - pstart), pstart);
+ return false;
+}
+
+const char* ffDetectInitSystem(FFInitSystemResult* result) {
+ const char* error = ffProcessGetBasicInfoLinux((int) result->pid, &result->name, NULL, NULL);
+ if (error) {
+#ifdef __ANDROID__
+ if (access("/system/bin/init", F_OK) == 0) {
+ ffStrbufSetStatic(&result->exe, "/system/bin/init");
+ ffStrbufSetStatic(&result->name, "init");
+ return NULL;
+ }
+#endif
+ return error;
+ }
+
+ const char* _;
+ // In linux /proc/1/exe is not readable
+ ffProcessGetInfoLinux((int) result->pid, &result->name, &result->exe, &_, NULL);
+ if (result->exe.chars[0] == '/') {
+ // In some old system, /sbin/init is a symlink
+ char buf[PATH_MAX];
+ if (realpath(result->exe.chars, buf)) {
+ ffStrbufSetS(&result->exe, buf);
+ ffStrbufSetS(&result->name, basename(result->exe.chars));
+ }
+ }
+
+ if (instance.config.general.detectVersion) {
+#if (defined(__linux__) && !defined(__ANDROID__)) || defined(__GNU__)
+ if (ffStrbufEqualS(&result->name, "systemd")) {
+ ffBinaryExtractStrings(result->exe.chars, extractSystemdVersion, &result->version, (uint32_t) strlen("systemd 0.0 running in x"));
+ if (result->version.length == 0) {
+ if (ffProcessAppendStdOut(&result->version, (char* const[]) {
+ ffStrbufEndsWithS(&result->exe, "/systemd") ? result->exe.chars : "systemctl", // use exe path in case users have another systemd installed
+ "--version",
+ NULL,
+ }) == NULL &&
+ result->version.length) {
+ uint32_t iStart = ffStrbufFirstIndexC(&result->version, '(');
+ if (iStart < result->version.length) {
+ uint32_t iEnd = ffStrbufNextIndexC(&result->version, iStart + 1, ')');
+ ffStrbufSubstrBefore(&result->version, iEnd);
+ ffStrbufSubstrAfter(&result->version, iStart);
+ }
+ }
+ }
+ } else if (ffStrbufEqualS(&result->name, "dinit")) {
+ if (ffProcessAppendStdOut(&result->version, (char* const[]) {
+ ffStrbufEndsWithS(&result->exe, "/dinit") ? result->exe.chars : "dinit",
+ "--version",
+ NULL,
+ }) == NULL &&
+ result->version.length) {
+ // Dinit version 0.18.0.
+ ffStrbufSubstrBeforeFirstC(&result->version, '\n');
+ ffStrbufTrimRight(&result->version, '.');
+ ffStrbufSubstrAfterLastC(&result->version, ' ');
+ }
+ } else if (ffStrbufEqualS(&result->name, "shepherd")) {
+ if (ffProcessAppendStdOut(&result->version, (char* const[]) {
+ ffStrbufEndsWithS(&result->exe, "/shepherd") ? result->exe.chars : "shepherd",
+ "--version",
+ NULL,
+ }) == NULL &&
+ result->version.length) {
+ // shepherd (GNU Shepherd) 1.0.6
+ // The first line in the output might not contain the version
+ if (!ffStrbufStartsWithS(&result->version, "shepherd")) {
+ ffStrbufSubstrAfterFirstC(&result->version, '\n');
+ }
+
+ ffStrbufSubstrBeforeFirstC(&result->version, '\n');
+ ffStrbufSubstrAfterLastC(&result->version, ' ');
+ }
+ }
+#elif __APPLE__
+ if (ffStrbufEqualS(&result->name, "launchd")) {
+ if (ffProcessAppendStdOut(&result->version, (char* const[]) {
+ "/bin/launchctl",
+ "version",
+ NULL,
+ }) == NULL &&
+ result->version.length) {
+ uint32_t iStart = ffStrbufFirstIndexS(&result->version, "Version ");
+ if (iStart < result->version.length) {
+ iStart += (uint32_t) strlen("Version");
+ uint32_t iEnd = ffStrbufNextIndexC(&result->version, iStart + 1, ':');
+ ffStrbufSubstrBefore(&result->version, iEnd);
+ ffStrbufSubstrAfter(&result->version, iStart);
+ }
+ }
+ }
+#endif
+ }
+
+ return NULL;
+}