123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- #include "platform.h"
- #if defined(_solaris_)
- #include <stdlib.h>
- #elif defined(_darwin_)
- #include <mach-o/dyld.h>
- #include <util/generic/function.h>
- #elif defined(_win_)
- #include "winint.h"
- #include <io.h>
- #elif defined(_linux_)
- #elif defined(_freebsd_)
- #include <string.h>
- #include <sys/types.h> // for u_int not defined in sysctl.h
- #include <sys/sysctl.h>
- #include <unistd.h>
- #endif
- #include <util/generic/singleton.h>
- #include "execpath.h"
- #include "fs.h"
- #if defined(_freebsd_)
- static inline bool GoodPath(const TString& path) {
- return path.find('/') != TString::npos;
- }
- static inline int FreeBSDSysCtl(int* mib, size_t mibSize, TTempBuf& res) {
- for (size_t i = 0; i < 2; ++i) {
- size_t cb = res.Size();
- if (sysctl(mib, mibSize, res.Data(), &cb, nullptr, 0) == 0) {
- res.Proceed(cb);
- return 0;
- } else if (errno == ENOMEM) {
- res = TTempBuf(cb);
- } else {
- return errno;
- }
- }
- return errno;
- }
- static inline TString FreeBSDGetExecPath() {
- int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
- TTempBuf buf;
- int r = FreeBSDSysCtl(mib, Y_ARRAY_SIZE(mib), buf);
- if (r == 0) {
- return TString(buf.Data(), buf.Filled() - 1);
- } else if (r == ENOTSUP) { // older FreeBSD version
- /*
- * BSD analogue for /proc/self is /proc/curproc.
- * See:
- * https://www.freebsd.org/cgi/man.cgi?query=procfs&sektion=5&format=html
- */
- TString path("/proc/curproc/file");
- return NFs::ReadLink(path);
- } else {
- return TString();
- }
- }
- static inline TString FreeBSDGetArgv0() {
- int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_ARGS, getpid()};
- TTempBuf buf;
- int r = FreeBSDSysCtl(mib, Y_ARRAY_SIZE(mib), buf);
- if (r == 0) {
- return TString(buf.Data());
- } else if (r == ENOTSUP) {
- return TString();
- } else {
- ythrow yexception() << "FreeBSDGetArgv0() failed: " << LastSystemErrorText();
- }
- }
- static inline bool FreeBSDGuessExecPath(const TString& guessPath, TString& execPath) {
- if (NFs::Exists(guessPath)) {
- // now it should work for real
- execPath = FreeBSDGetExecPath();
- if (RealPath(execPath) == RealPath(guessPath)) {
- return true;
- }
- }
- return false;
- }
- static inline bool FreeBSDGuessExecBasePath(const TString& guessBasePath, TString& execPath) {
- return FreeBSDGuessExecPath(TString(guessBasePath) + "/" + getprogname(), execPath);
- }
- #endif
- static TString GetExecPathImpl() {
- #if defined(_solaris_)
- return execname();
- #elif defined(_darwin_)
- TTempBuf execNameBuf;
- for (size_t i = 0; i < 2; ++i) {
- std::remove_pointer_t<TFunctionArg<decltype(_NSGetExecutablePath), 1>> bufsize = execNameBuf.Size();
- int r = _NSGetExecutablePath(execNameBuf.Data(), &bufsize);
- if (r == 0) {
- return execNameBuf.Data();
- } else if (r == -1) {
- execNameBuf = TTempBuf(bufsize);
- }
- }
- ythrow yexception() << "GetExecPathImpl() failed";
- #elif defined(_win_)
- TTempBuf execNameBuf;
- for (;;) {
- DWORD r = GetModuleFileName(nullptr, execNameBuf.Data(), execNameBuf.Size());
- if (r == execNameBuf.Size()) {
- execNameBuf = TTempBuf(execNameBuf.Size() * 2);
- } else if (r == 0) {
- ythrow yexception() << "GetExecPathImpl() failed: " << LastSystemErrorText();
- } else {
- return execNameBuf.Data();
- }
- }
- #elif defined(_linux_) || defined(_cygwin_)
- TString path("/proc/self/exe");
- return NFs::ReadLink(path);
- // TODO(yoda): check if the filename ends with " (deleted)"
- #elif defined(_freebsd_)
- TString execPath = FreeBSDGetExecPath();
- if (GoodPath(execPath)) {
- return execPath;
- }
- if (FreeBSDGuessExecPath(FreeBSDGetArgv0(), execPath)) {
- return execPath;
- }
- if (FreeBSDGuessExecPath(getenv("_"), execPath)) {
- return execPath;
- }
- if (FreeBSDGuessExecBasePath(getenv("PWD"), execPath)) {
- return execPath;
- }
- if (FreeBSDGuessExecBasePath(NFs::CurrentWorkingDirectory(), execPath)) {
- return execPath;
- }
- ythrow yexception() << "can not resolve exec path";
- #else
- #error dont know how to implement GetExecPath on this platform
- #endif
- }
- static bool GetPersistentExecPathImpl(TString& to) {
- #if defined(_solaris_)
- to = TString("/proc/self/object/a.out");
- return true;
- #elif defined(_linux_) || defined(_cygwin_)
- to = TString("/proc/self/exe");
- return true;
- #elif defined(_freebsd_)
- to = TString("/proc/curproc/file");
- return true;
- #else // defined(_win_) || defined(_darwin_) or unknown
- Y_UNUSED(to);
- return false;
- #endif
- }
- namespace {
- struct TExecPathsHolder {
- inline TExecPathsHolder() {
- ExecPath = GetExecPathImpl();
- if (!GetPersistentExecPathImpl(PersistentExecPath)) {
- PersistentExecPath = ExecPath;
- }
- }
- static inline auto Instance() {
- return SingletonWithPriority<TExecPathsHolder, 1>();
- }
- TString ExecPath;
- TString PersistentExecPath;
- };
- } // namespace
- const TString& GetExecPath() {
- return TExecPathsHolder::Instance()->ExecPath;
- }
- const TString& GetPersistentExecPath() {
- return TExecPathsHolder::Instance()->PersistentExecPath;
- }
|