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

WilliamKF picture WilliamKF · Mar 10, 2015 · Viewed 11.8k times · Source

In my C++ application, my application does an execv() in a fork()ed child process to use the same executable to process some work in a new child process with different arguments that communicates with pipes to the parent process. To get the pathname to self, I execute the following code on the Linux port (I have different code on Macintosh):

  const size_t bufSize = PATH_MAX + 1;
  char dirNameBuffer[bufSize];
  // Read the symbolic link '/proc/self/exe'.
  const char *linkName = "/proc/self/exe";
  const int ret = int(readlink(linkName, dirNameBuffer, bufSize - 1));

However, if while the executable is running, I replace the executable with an updated version of the binary on disk, the readlink() string result is: "/usr/local/bin/myExecutable (deleted)"

I understand that my executable has been replaced by a newer updated version and the original for /proc/self/exe is now replaced, however, when I go to execv() it now fails with the errno 2 - No such file or directory. due to the extra trailing " (deleted)" in the result.

I would like the execv() to either use the old executable for self, or the updated one. I could just detect the string ending with " (deleted)" and modify it to omit that and resolve to the updated executable, but that seems clumsy to me.

How can I execv() the current executable (or its replacement if that is easier) with a new set of arguments when the original executable has been replaced by an updated one during execution?

Answer

andrewrk picture andrewrk · Aug 17, 2016

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.