WilliamKF WilliamKF - 3 months ago 16
Linux Question

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

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

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.