Here it says that you can rewrite an executable file and the process will run just fine – it will be re-read when a process restarts.
However, when I try to replace a binary file while the process is running (with scp, from dev to test server) it says ‘file busy’. And if I replace a shared library file (*.so), all the processes that link it crash.
Why so? Am I missing something? How can I replace the binary files without stopping/crashing a process?
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
As mentioned in Why does a software package run just fine even when it is being upgraded?, the lock is placed on inode not on filename. When you load and execute a binary, the the file is marked as busy – which is why you get ETXTBSY (file busy) error when you try to write to it.
Now, for shared libraries it is slightly different: the libraries get memory mapped into the process’ address space with
MAP_DENYWRITE may be specified, at least Glibc on Linux silently ignores it (according to the man page, feel free to check the sources) – check this thread. Hence you actually are allowed to write the file and, as it is memory mapped, any changes are visible almost immediately – which means that if you try hard enough you can manage to brick your machine by overwriting the library.
The correct way to update therefore is:
- removing the file, which removes reference to the data from the file system, so that it isn’t accessible for any newly spawned applications that might want to use it, while keeping the data accessible for anyone who already has it open (or mapped);
- creating a new file with updated contents.
Newly created processes will use the updated contents, running applications will access the old version. This is what any sane package management utility does. Note that it’s not completely without any danger though – for example applications dynamically loading code (using
dlsym() and friends) will experience troubles if the library’s API changes silently.
If you want to be on the really, really safe side, shut down the system, mount the file system from another operating system instance, update and bring up the updated system again.
A rpm upgrade does the same – with running binaries and libraries while nothing crashes.
So what is the difference:
- unlink file
- write new file with the same name
This will NOT replace the file inplace: The inode referring to the in-use-binary is still “busy” until the last object holding it open finishes. The new file will be created with a new inode-number.
cp will try to replace the file inplace – which would change the content the inode is referring to. This does not work – as you described.