1

argv[0] references the shell command that caused the current process to load. getcwd() returns current working directory. From that info, can I construct an absolute path to the program's binary executable file? I don't expect it to work if the program has done a cd since it was first loaded.

  • argv[0] could be anything, see unix.stackexchange.com/a/315819/64248. – countermode Oct 18 '16 at 14:27
  • The current working directory is not relevant, the executable file is searched in the directories listed in the PATH environment variable. What complicates matters even more is that POSIX defines the function fexecve(int fd, char *const argv[], char *const envp), which "executes a program specified via a file descriptor". This library function is implemented on Linux using the /proc file system, and argv[0] contains something like "/proc/self/fd/4". There really is no robust way to get the executable file, there might not even be one! – Johan Myréen Oct 18 '16 at 15:48
  • @countermode Although argv[0] could be anything, you can make it a documented requirement for your program that certain features of it (perhaps all of them) require it to calculate its own path, which (at least on some platforms) requires argv[0] to be non-null, and with a sane value: the path, perhaps relative to cwd, by which it was invoked. Any program can be misused contrary to its documented correct use, with invalid arguments or other situations. – Kaz Oct 18 '16 at 16:47
2

In the internals of a programming language interpreter, I use the following code to get the self path:

#if __linux__
static val get_self_path(void)
{
  char self[PATH_MAX] = { 0 };
  int nchar = readlink("/proc/self/exe", self, sizeof self);

  if (nchar < 0 || nchar >= convert(int, sizeof self))
    return nil;
  return string_utf8(self);
}
#elif HAVE_WINDOWS_H
static val get_self_path(void)
{
  wchar_t self[MAX_PATH] = { 0 };
  DWORD nchar;

  SetLastError(0);
  nchar = GetModuleFileNameW(NULL, self, MAX_PATH);

  if (nchar == 0 ||
      (nchar == MAX_PATH &&
       ((GetLastError() == ERROR_INSUFFICIENT_BUFFER) ||
        (self[MAX_PATH - 1] != 0))))
    return nil;

  return string(self);
}
#else
static val get_self_path(void)
{
  char self[PATH_MAX];

  if (!progname_u8)
    return nil;

  if (realpath(progname_u8, self))
    return string_utf8(self);

  return nil;
}
#endif

The val type, nil symbol, and the functions string and string_utf8 are internal to the interpreter. convert is just a macro that abstracts casting. Of course, some header files are required for readlink, realpath and so on.

progname_u8 is just a global variable initialized directly from argv[0]. in a Unix that isn't Linux, we use that and call realpath on it to get an absolute path.

1

On Linux you can use the symlink /proc/self/exe

$ ls -l  /proc/self/exe
lrwxrwxrwx 1 rudi users 0 2016-10-18 16:20 /proc/self/exe -> /usr/bin/ls

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.