Respostas:
Conforme mencionado por @Kusalananda, geralmente as atualizações são feitas removendo o arquivo antigo e criando um novo com o mesmo nome. Na verdade, isso criará um novo arquivo com um novo inode, deixando o sistema livre para usar o antigo enquanto estiver aberto.
Como um exemplo simplificado, coisas como
rm /bin/cat
cp /new/version/of/cat /bin/cat
criará um arquivo logicamente novo e funcionará mesmo que cat
esteja em execução. O mesmo vale para as bibliotecas. (O exemplo acima é um exemplo, não uma maneira robusta de atualizar um arquivo no mundo real.)
Alguém poderia tentar alterar o binário no local em vez de criar um novo com o mesmo nome. Nesse caso, pelo menos o Linux realmente impede fazer alterações em um executável em uso:
window 1 # ./cat
window 2 # echo foobar > cat
-bash: cat: Text file busy
No entanto, isso não parece funcionar com bibliotecas carregadas dinamicamente ...
Fiz uma cópia libc.so.6
para teste e a preenchi com zeros enquanto estava em uso:
window 1 /tmp/lib# LD_LIBRARY_PATH=/tmp/lib ldd ./cat
linux-vdso.so.1 (0x00007ffcfaf30000)
libc.so.6 => /tmp/lib/libc.so.6 (0x00007f1145e67000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1146212000)
window 1 /tmp/lib# LD_LIBRARY_PATH=/tmp/lib ./cat
foo
foo
Segmentation fault
(Enquanto isso, em outra janela, após o foo
, antes do segfault)
window 2 /tmp/lib# dd if=/dev/zero of=libc.so.6 bs=1024 count=2000
Não há realmente nada que o próprio programa possa fazer contra isso, desde que efetivamente editei seu código online.
(Isso provavelmente dependerá do sistema, testei no Debian Jessie 8.5, Linux 3.16.7-ckt25-2 + deb8u3. Os sistemas Windows IIRC em particular são ainda mais agressivos ao impedir a modificação de arquivos em uso.)
Portanto, acho que a resposta é que as atualizações geralmente são feitas de maneira a evitar problemas, e isso é ajudado pelos componentes internos do sistema de arquivos. Mas (no Linux) não parece haver nenhuma proteção contra bibliotecas dinâmicas realmente corrompidas.
install
utilitário é comumente usado para coisas como esta. Você não precisa explicitamente rm
o arquivo de destino. Além disso, ele preserva as permissões do arquivo existente, pode fazer uma cópia de segurança, definir um novo modo, etc. Exemplo de uso:install /new/version/of/cat /bin/cat
rm
+ cp
foi usado como exemplo. Também pode ser inteligente colocar o novo arquivo no lugar atomicamente com uma renomeação, para evitar uma pequena janela na qual nenhuma versão está disponível. (Embora GNU install
não parece mesmo fazer isso, hmpf.)
rm
), ele ainda não será excluído. Ele existirá no disco e ainda poderá ser lido por todos os processos que o abrirem. Ele será excluído apenas quando a contagem de links físicos atingir zero E o número de precesses com o arquivo aberto atingir zero.
install
utilitário é especificamente inseguro! Ele substitui o arquivo de destino no lugar, em vez de substituí-lo atomicamente. mv
(com origem e destino no mesmo diretório, fonte geralmente um arquivo temporário) é a única maneira segura de instalar arquivos.
strace
, install
no GNU coreutils desvincula o arquivo de destino e depois copia um novo em seu lugar. O que significa que existe uma janela curta durante a qual o arquivo é parcial. Ele não define o arquivo atomicamente no lugar com uma renomeação.
Os arquivos não serão "excluídos corretamente" se forem desvinculados enquanto ainda estão abertos. Quando eles estiverem fechados, o espaço em disco que eles usaram será considerado "livre" novamente. Isso vale para aplicativos em execução no momento e suas bibliotecas compartilhadas também.
A única coisa que eu via falha seria se um programa usasse dlopen()
uma biblioteca compartilhada sob demanda ou se o programa precisasse acessar outros arquivos sob demanda, como dicionários, arquivos de temas ou outros arquivos que desapareceram repentinamente.
Para ilustrar: A execução vim
em uma sessão de shell e a instalação de vim
outra sessão de shell não "corromperão" nem encerrarão a vim
sessão atualmente em execução . Mas algumas coisas começam a falhar, como a verificação ortográfica, por exemplo, que requer vim
a abertura de arquivos em sua instalação.
ln -sf
ao trocar de bibliotecas, porque isso-f
permite que você "sobrescreva" o destino existente do link simbólico por um novo, sem que ele nunca seja "quebrado" (diferente de se vocêrm
seguisse aln -s
) Portanto, antes do comando, library.so apontou para a versão antiga, por exemplo. library.so.4 ... após o comando, ele simplesmente apontou para library.so.5 (ou qualquer outro) em vez - sem nunca não apontando para uma biblioteca válido.