diff --git a/Userland/Libraries/LibCore/System.cpp b/Userland/Libraries/LibCore/System.cpp index feb1dee6a2b..f4ee758761c 100644 --- a/Userland/Libraries/LibCore/System.cpp +++ b/Userland/Libraries/LibCore/System.cpp @@ -44,11 +44,16 @@ static int memfd_create(char const* name, unsigned int flags) #if defined(AK_OS_MACOS) # include +# include # include #else extern char** environ; #endif +#if defined(AK_OS_BSD_GENERIC) +# include +#endif + #define HANDLE_SYSCALL_RETURN_VALUE(syscall_name, rc, success_value) \ if ((rc) < 0) { \ return Error::from_syscall(syscall_name##sv, rc); \ @@ -1726,4 +1731,42 @@ char** environment() #endif } +ErrorOr current_executable_path() +{ + char path[4096] = {}; +#if defined(AK_OS_LINUX) || defined(AK_OS_ANDROID) || defined(AK_OS_SERENITY) + auto ret = ::readlink("/proc/self/exe", path, sizeof(path) - 1); + // Ignore error if it wasn't a symlink + if (ret == -1 && errno != EINVAL) + return Error::from_syscall("readlink"sv, -errno); +#elif defined(AK_OS_DRAGONFLY) + return String::from_deprecated_string(TRY(readlink("/proc/curproc/file"sv))); +#elif defined(AK_OS_SOLARIS) + return String::from_deprecated_string(TRY(readlink("/proc/self/path/a.out"sv))); +#elif defined(AK_OS_FREEBSD) + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + size_t len = sizeof(path); + if (sysctl(mib, 4, path, &len, nullptr, 0) < 0) + return Errno::from_syscall("sysctl"sv, -errno); +#elif defined(AK_OS_NETBSD) + int mib[4] = { CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME }; + size_t len = sizeof(path); + if (sysctl(mib, 4, path, &len, nullptr, 0) < 0) + return Errno::from_syscall("sysctl"sv, -errno); +#elif defined(AK_OS_MACOS) + u32 size = sizeof(path); + auto ret = _NSGetExecutablePath(path, &size); + if (ret != 0) + return Error::from_errno(ENAMETOOLONG); +#elif defined(AK_OS_EMSCRIPTEN) + return Error::from_string_view("current_executable_path() unknown on this platform"sv); +#else +# warning "Not sure how to get current_executable_path on this platform!" + // GetModuleFileName on Windows, unsure about OpenBSD. + return Error::from_string_view("current_executable_path unknown"sv); +#endif + path[sizeof(path) - 1] = '\0'; + return String::from_utf8({ path, strlen(path) }); +} + } diff --git a/Userland/Libraries/LibCore/System.h b/Userland/Libraries/LibCore/System.h index 41f971a8e89..1ec1b59a157 100644 --- a/Userland/Libraries/LibCore/System.h +++ b/Userland/Libraries/LibCore/System.h @@ -273,4 +273,6 @@ ErrorOr resolve_executable_from_environment(StringView filename, int fla char** environment(); +ErrorOr current_executable_path(); + }