LibCore: Add Core::System::current_executable_path()

This is based on Jakt::File::current_executable_path() and all the other
sources I looked at to figure out the per-platform way to do this. My
goodness, every platform has its own bespoke way.
This commit is contained in:
Andrew Kaster 2023-08-02 16:56:53 -06:00 committed by Andreas Kling
parent 88ccaae11e
commit bb831a27dd
2 changed files with 45 additions and 0 deletions

View file

@ -44,11 +44,16 @@ static int memfd_create(char const* name, unsigned int flags)
#if defined(AK_OS_MACOS)
# include <crt_externs.h>
# include <mach-o/dyld.h>
# include <sys/mman.h>
#else
extern char** environ;
#endif
#if defined(AK_OS_BSD_GENERIC)
# include <sys/sysctl.h>
#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<String> 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) });
}
}

View file

@ -273,4 +273,6 @@ ErrorOr<String> resolve_executable_from_environment(StringView filename, int fla
char** environment();
ErrorOr<String> current_executable_path();
}