Por que é possível mover um programa em execução no Ubuntu?

22

Acabei de perceber que sou capaz de mover um programa ativo em execução para um diretório diferente. Na minha experiência, isso não era possível no MacOs ou no Windows. Como funciona no Ubuntu?

Edit: Eu pensei que não era possível no Mac, mas aparentemente é possível como os comentários confirmam. Só não é possível no Windows talvez. Obrigado por todas as respostas.

    
por n0.ob 19.08.2016 / 15:45

6 respostas

28

Deixe-me dividi-lo.

Quando você executa um executável, uma seqüência de chamadas do sistema é executada, principalmente fork() e execve() :

  • fork() cria um processo filho do processo de chamada, que é (principalmente) uma cópia exata do pai, ambos ainda executando o mesmo executável (usando páginas de memória copy-on-write, portanto, é eficiente) . Ele retorna duas vezes: no pai, retorna o PID filho. No filho, ele retorna 0. Normalmente, o processo filho chama execve imediatamente:

  • execve() toma um caminho completo para o executável como um argumento e substitui o processo de chamada pelo executável. Neste ponto, o processo recém-criado obtém seu próprio espaço de endereço virtual, ou seja, memória virtual, e a execução começa em seu ponto de entrada (em um estado especificado pelas regras da plataforma ABI para novos processos).

Neste ponto, o carregador ELF do kernel mapeou o texto e dados segmentos do executável na memória, como se tivesse usado o mmap() chamada de sistema (com mapeamentos de leitura-gravação compartilhados e somente leitura respectivamente). O BSS também é mapeado como se com MAP_ANONYMOUS. (BTW, estou ignorando a vinculação dinâmica aqui para simplificar: o vinculador dinâmico open() se mmap() s todas as bibliotecas dinâmicas antes de pular para o ponto de entrada do executável principal.)

Apenas algumas páginas são realmente carregadas na memória do disco antes de um recém-executado executar o seu próprio código. Outras páginas são pagas paginadas conforme necessário, se / quando o processo tocar essas partes de seu espaço de endereço virtual. (O pré-carregamento de qualquer página de código ou dados antes de começar a executar o código do espaço do usuário é apenas uma otimização de desempenho.)

O arquivo executável é identificado pelo inode no nível inferior. Depois que o arquivo começou a ser executado, o kernel mantém o conteúdo do arquivo intacto pela referência do inode, não pelo nome do arquivo, como para descritores de arquivos abertos ou mapeamentos de memória com backup de arquivos. Assim, você pode facilmente mover o executável para outro local do sistema de arquivos ou até mesmo em um sistema de arquivos diferente. Como uma nota lateral, para verificar várias estatísticas do processo, você pode espiar no diretório /proc/PID (PID é o ID do processo de determinado processo). Você pode até mesmo abrir o arquivo executável como /proc/PID/exe , mesmo que ele tenha sido desvinculado do disco.

Agora vamos analisar o movimento:

Quando você move um arquivo dentro de um mesmo sistema de arquivos, a chamada do sistema que é executada é rename() , que apenas renomeia o arquivo para outro nome, o inode do arquivo permanece o mesmo.

Considerando que entre dois sistemas de arquivos diferentes, duas coisas acontecem:

  • O conteúdo do arquivo é copiado primeiro para o novo local, por read() e write()

  • Depois disso, o arquivo é desvinculado do diretório de origem usando unlink() e, obviamente, o arquivo receberá um novo inode no novo sistema de arquivos.

rm é na verdade apenas unlink() -ing do arquivo fornecido na árvore de diretórios, portanto, ter a permissão de gravação no diretório fornecerá a você o direito de remover qualquer arquivo desse diretório.

Agora, por diversão, imagine o que acontece quando você está movendo arquivos entre dois arquivos e não tem permissão para unlink() do arquivo da fonte?

Bem, o arquivo será copiado para o destino inicialmente ( read() , write() ) e, em seguida, unlink() falhará devido a permissão insuficiente. Então, o arquivo permanecerá em ambos os sistemas de arquivos!

    
por heemayl 19.08.2016 / 20:17
13

Bem, isso é bem direto. Vamos pegar um executável chamado / usr / local / bin / whoopdeedoo. Isso é apenas uma referência ao chamado inode (estrutura básica dos arquivos em Unix Filesystems). É o inode que é marcado como "em uso".

Agora, quando você excluir ou mover o arquivo / usr / local / whoopdeedoo, a única coisa que é movida (ou apagada) é a referência ao inode. O inode em si permanece inalterado. Basicamente é isso.

Eu deveria verificar isso, mas acredito que você também pode fazer isso em sistemas de arquivos do Mac OS X.

O Windows usa uma abordagem diferente. Por quê? Quem sabe...? Eu não estou familiarizado com os internos do NTFS. Teoricamente, todos os sistemas de arquivos que usam referências a estruturas intenais para nomes de arquivos devem ser capazes de fazer isso.

Eu admito, eu simplifiquei demais, mas vou ler a seção "Implicações" na Wikipedia, que faz um trabalho muito melhor do que eu.

    
por jawtheshark 19.08.2016 / 16:02
12

Uma coisa que parece ausente de todas as outras respostas é que: uma vez que um arquivo é aberto e um programa contém um descritor de arquivo aberto o arquivo não será removido do sistema até que o descritor de arquivo seja fechado

As tentativas de excluir o inode mencionado serão atrasadas até que o arquivo seja fechado: renomear no mesmo sistema de arquivos ou em um sistema de arquivos diferente não afeta o arquivo aberto, independentemente do comportamento da renomeação, nem excluir ou substituir explicitamente o arquivo por um novo 1. A única maneira em que você pode mexer em um arquivo é abrir explicitamente seu inode e mexer com o conteúdo, não por operações no diretório, como renomear / excluir o arquivo.

Além disso, quando o kernel executa um arquivo, ele mantém uma referência ao arquivo executável e isso evitará novamente qualquer modificação durante a execução.

Então, no final, mesmo que pareça que você possa apagar / mover os arquivos que compõem um programa em execução, na verdade, o conteúdo desses arquivos é mantido na memória até que o programa termine .

    
por Bakuriu 19.08.2016 / 21:52
7

Em um sistema de arquivos Linux, quando você move um arquivo, desde que não ultrapasse os limites do sistema de arquivos (leia: permanece no mesmo disco / partição), tudo o que você está alterando é o inode de .. (diretório pai) ao do novo local. Os dados reais não foram movidos no disco, apenas o ponteiro para que o sistema de arquivos saiba onde encontrá-lo.

É por isso que as operações de movimentação são tão rápidas e prováveis ​​por que não há problema em mover um programa em execução, já que você não está realmente movendo o programa em si.

    
por I_GNU_it_all_along 19.08.2016 / 16:01
6

É possível, porque mover um programa não afeta os processos em execução iniciados ao iniciá-lo.

Quando um programa é iniciado, seus bits no disco são protegidos contra sobrescritos, mas não há necessidade de proteger o arquivo a ser renomeado, movido para um local diferente no mesmo sistema de arquivos, o que equivale a renomear o arquivo ou movido para um sistema de arquivos diferente, o que equivale a copiar o arquivo em outro lugar e, em seguida, removê-lo.

A remoção de um arquivo que está em uso, seja porque um processo tem um descritor de arquivo aberto ou porque um processo o está executando, não remove os dados do arquivo, que permanece referenciado pelo inode do arquivo, mas apenas remove o arquivo. entrada de diretório, ou seja, um caminho a partir do qual o inode pode ser alcançado.

Observe que o lançamento de um programa não carrega tudo de uma vez na memória (física). Pelo contrário, apenas o mínimo rigoroso necessário para o processo iniciar é carregado. Então, as páginas necessárias são carregadas sob demanda durante toda a vida do processo. isso é chamado de paginação por demanda. Se houver falta de memória RAM, o sistema operacional estará livre para liberar a memória RAM que contém essas páginas, de modo que seja bem possível que um processo carregue várias vezes a mesma página do inode executável.

A razão pela qual não era possível com o Windows é originalmente provável devido ao fato de o sistema de arquivos subjacente (FAT) não estar suportando o conceito de divisão de entradas de diretório vs inodes. Essa limitação não estava mais presente no NTFS, mas o design do SO foi mantido por um longo tempo, levando à restrição desagradável de ter que reinicializar ao instalar uma nova versão de um binário, o que não é mais o caso com versões recentes do Windows.

    
por jlliagre 20.08.2016 / 02:10
4

Basicamente, no Unix e em seu gênero, um nome de arquivo (incluindo o caminho do diretório que leva a ele) é usado para associar / encontrar um arquivo quando abrir ele (executar um arquivo é uma maneira de abrir de uma maneira). Após esse momento, a identidade do arquivo (via seu "inode") é estabelecida e não mais questionada. Você pode remover o arquivo, renomeá-lo, alterar suas permissões. Contanto que qualquer processo ou caminho de arquivo tenha um identificador naquele arquivo / inode, ele permanecerá, assim como um pipe entre os processos (na verdade, no histórico UNIX um pipe era um inode sem nome com um tamanho que apenas se encaixa na referência de armazenamento em disco "blocos diretos" no inode, algo como 10 blocos).

Se você tiver um visualizador de PDF aberto em um arquivo PDF, poderá excluí-lo e abrir um novo com o mesmo nome. Enquanto o antigo visualizador estiver aberto, ele ainda estará bem acessando o arquivo antigo (a menos que vigia ativamente o sistema de arquivos para perceber quando o arquivo desaparece sob seu nome original).

Os programas que precisam de arquivos temporários podem simplesmente abrir um arquivo com algum nome e, em seguida, imediatamente removê-lo (ou melhor, sua entrada de diretório) enquanto ele ainda estiver aberto. Depois, o arquivo não é mais acessível pelo nome, mas qualquer processo que tenha um descritor de arquivo aberto para o arquivo ainda poderá acessá-lo e, se houver uma saída inesperada do programa, o arquivo será removido e o armazenamento será recuperado automaticamente. / p>

Portanto, o caminho para um arquivo não é uma propriedade do próprio arquivo (na verdade, hard links podem fornecer vários caminhos diferentes) e é necessário apenas para abri-lo, não para acesso contínuo por processos que já o abrem. / p>     

por user584745 21.08.2016 / 11:29