Finding Current Executable'S Path Without /Proc/Self/Exe

Size of an executable at runtime in C/C++ on Linux without /proc/self/exe?

dl_iterate_phdr

https://linux.die.net/man/3/dl_iterate_phdr

This solved it! Thanks @o11c!

What could break /proc/self/exe?

So the cause turned out to be UPX (executable compressor). I hadn't thought of it earlier because it was included in my build pipeline. Apparently, on some systems it doesn't extract to memory but uses a temp file, which caused this error. Am still puzzled why the trace output doesn't show a rename, but alas.

How do I find the location of the executable in C? [duplicate]

To summarize:

  • On Unixes with /proc really straight and realiable way is to:

    • readlink("/proc/self/exe", buf, bufsize) (Linux)

    • readlink("/proc/curproc/file", buf, bufsize) (FreeBSD)

    • readlink("/proc/self/path/a.out", buf, bufsize) (Solaris)

  • On Unixes without /proc (i.e. if above fails):

    • If argv[0] starts with "/" (absolute path) this is the path.

    • Otherwise if argv[0] contains "/" (relative path) append it to cwd
      (assuming it hasn't been changed yet).

    • Otherwise search directories in $PATH for executable argv[0].

    Afterwards it may be reasonable to check whether the executable isn't actually a symlink.
    If it is resolve it relative to the symlink directory.

    This step is not necessary in /proc method (at least for Linux).
    There the proc symlink points directly to executable.

    Note that it is up to the calling process to set argv[0] correctly.
    It is right most of the times however there are occasions when the calling process cannot be trusted (ex. setuid executable).

  • On Windows: use GetModuleFileName(NULL, buf, bufsize)

Getting length of /proc/self/exe symlink

In practice, I would tend to use a reasonable size (e.g. 256 or 1024, or PATH_MAX) for readlink of /proc/*/exe (or /proc/self/exe)

The point is that almost always, executables are supposed to be started by humans, so either the PATH (for execvp(3) or some shell) or the entire file path is human friendly. I don't know any people who explicitly uses very long filenames (not fitting in width in some terminal screen). I never heard of executable programs (or scripts) whose filename exceeds a hundred of bytes.

So just use a local buffer of some reasonable size (and perhaps strdup it on success if so needed). And readlink(2) returns the number of meaningful bytes in its buffer (so if you really care, grow the buffer and make a loop till it fits).

For readlink of /proc/self/exe, I would do it into a 256 bytes buffer at initialization, and abort (with a meaningful error message) if it does not fit (or fail, e.g. because /proc/ is not mounted).

How to handle readlink() of /proc/self/exe when executable is replaced during execution?

Instead of using readlink to discover the path to your own executable, you can directly call open on /proc/self/exe. Since the kernel already has an open fd to processes that are currently executing, this will give you an fd regardless of whether the path has been replaced with a new executable or not.

Next, you can use fexecve instead of execv which accepts an fd parameter instead of a filename parameter for the executable.

int fd = open("/proc/self/exe", O_RDONLY);
fexecve(fd, argv, envp);

Above code omits error handling for brevity.

Get executable's path (with std::filesystem) [duplicate]

No, there's nothing provided in the standard filesystem facilities to get the path of your executable.

Even using using the 1st argv argument isn't guaranteed to contain the full path of the executable.

The systems I know will just pass in the string that was used to launch the program.

Considering that this could be resolved using the PATH environment variable, there's no guarantee, you see a full path there.

There are some OS specific methods to do so though:

  • Get path of executable

how to find the location of the executable in C in OS X [duplicate]

Mac OS X implements the functions:

int _NSGetExecutablePath(char * buf, uint32_t * length);
int * _NSGetArgc(void);
char *** _NSGetArgv(void);

The first of these is probably what you want here. The other two are interesting as well, though!



Related Topics



Leave a reply



Submit