4

How does one determine the file that represents the current process' executable?

The problem is that argv[0] is not reliable, as if it was called via execXp, the path entry that satisfied a non-qualified command may or may not be prepended. Furthermore, ANY caller to exec* can replace argv[0] with ANYTHING.

Hence, if you run ps, you are not guaranteed that argv[0] will be "/usr/bin/ps". In fact, you're probably guaranteed the OPPOSITE.

I need one of the following:

  1. the full path name (without doing a path search myself, lest the envp I am using is not the one the shell used)
  2. a live, pre-opened file descriptor to the file that corresponds to the current process' image
  3. some magic descriptor that corresponds to the code segment currently in memory (not quite sure about the BSS segment, though)

In this way, at startup I can quickly open an FD to my own executable (for case 1., in case the file gets removed and becomes unopenable), and then at a much later date call:

int fexecve(int fd, char *const argv[], char *const envp[]);

to fork/exec myself (typically needed on OS-X to work around the unreliability of the global and system descriptor state after fork() ). In other words (this example is silly, of course):

void magicallyReplicate(argc, argv)
{
  if (!fork()) {
    magicallyExecMyself(argc, argv);
  }
}

or even just:

void startOver(argc, argv)
{
  magicallyExecMyself(argc, argv);
}

Of course, in my example, I will be using different argv's so that I can run in a different mode.

(early "no" retort: you can't use clone(), as it is of fork()'s lineage)

Sled
  • 18,541
  • 27
  • 119
  • 168
Mark Gerolimatos
  • 2,424
  • 1
  • 23
  • 33
  • `How does one determine the file that represents the current process' executable?`. Is it OK for you how pmap determines the file that represents a process? As an example it starts its output like this for example for bash process: `0000000000400000 848K r-x-- /bin/bash`. –  Nov 14 '13 at 05:42
  • Any way that gets me the path or an open FD is fine. I do not even believe the current seek point matters to fexecve. – Mark Gerolimatos Nov 14 '13 at 05:49
  • Then why don't you just read /proc/PID/maps? It contains in the first line the file name for a running process. –  Nov 14 '13 at 06:06
  • /proc/pid isn't POSIX compliant...otherwise, I would. Great idea though, would be great on LINUX! – Mark Gerolimatos Nov 14 '13 at 06:47
  • Your question has tag `linux` by the way –  Nov 14 '13 at 06:54
  • Great question! Several duplicates on SO already... – Nicholas Wilson Nov 14 '13 at 08:37
  • Also less-good answer but with a bit more discussion: http://stackoverflow.com/questions/933850/how-to-find-the-location-of-the-executable-in-c – Nicholas Wilson Nov 14 '13 at 08:49
  • @Nicholas...the problem is that while the question may be asked repeatedly, it's subtle enough that the format of the question(s) did not match previous incarnations, and thus were not matched. I spent a LONG time on The Google before giving up. In general, the subtle questions are going to be like this; much of the low-hanging fruit has been picked. And frankly, bully for the multiple asks: each one tends to be worded slightly differently, resulting in a better chance that a future querier will find without needing to ask. – Mark Gerolimatos Nov 15 '13 at 08:44

1 Answers1

2

So basically, the easiest platform to do this on is MacOS (because libc is totally broken and simple things like getaddrinfo segfault if called between fork and exec) - on Darwin, the kernel hands you on a plate the full binary name when it starts up the process. Retrieve it with the fourth argument to main (http://web.archive.org/web/20170816030258/http://unixjunkie.blogspot.com/2006/02/char-apple-argument-vector.html) or with _NSGetExecutablePath which is exactly the same - it's just a function that knows about the identical special position where the kernel puts the filename.

For all platforms, it's a case-by-case matter. Full details in this thread: Finding current executable's path without /proc/self/exe

Grisha Levit
  • 8,194
  • 2
  • 38
  • 53
Nicholas Wilson
  • 9,435
  • 1
  • 41
  • 80