Gostaria de saber como aplicativos matadores, como Thunderbird ou Firefox, podem ser atualizados através do gerenciador de pacotes do sistema enquanto eles ainda estão em execução. O que acontece com o código antigo enquanto eles estão sendo atualizados? O que tenho que fazer quando quero escrever um programa a.out que se atualize enquanto estiver em execução?
files
upgrade
executable
ubuplex
fonte
fonte
Respostas:
Substituindo arquivos em geral
Primeiro, existem várias estratégias para substituir um arquivo:
Abra o arquivo existente para gravação, trunque-o no tamanho 0 e escreva o novo conteúdo. (Uma variante menos comum é abrir o arquivo existente, substituir o conteúdo antigo pelo novo, truncar o arquivo para o novo tamanho, se for menor.) Em termos de shell:
Remova o arquivo antigo e crie um novo arquivo com o mesmo nome. Em termos de shell:
Escreva em um novo arquivo com um nome temporário e mova o novo arquivo para o nome existente. A movimentação exclui o arquivo antigo. Em termos de shell:
Não vou listar todas as diferenças entre as estratégias, apenas mencionarei algumas que são importantes aqui. Com a estratégia 1, se algum processo estiver usando o arquivo no momento, o processo verá o novo conteúdo enquanto ele está sendo atualizado. Isso pode causar alguma confusão se o processo esperar que o conteúdo do arquivo permaneça o mesmo. Observe que isso é apenas sobre processos que têm o arquivo aberto (como visível em
lsof
ou em ; aplicativos interativos que têm um documento aberto (por exemplo, abrir um arquivo em um editor) geralmente não mantêm o arquivo aberto, eles carregam o conteúdo do arquivo durante o processo. Operação "abrir documento" e eles substituem o arquivo (usando uma das estratégias acima) durante a operação "salvar documento"./proc/PID/fd/
Nas estratégias 2 e 3, se algum processo tiver o arquivo
somefile
aberto, o arquivo antigo permanecerá aberto durante a atualização do conteúdo. Com a estratégia 2, a etapa de remover o arquivo remove apenas a entrada do arquivo no diretório O arquivo em si só é removido quando não possui uma entrada de diretório que o conduza (em sistemas de arquivos Unix típicos, pode haver mais de uma entrada de diretório para o mesmo arquivo ) e nenhum processo o abre. Aqui está uma maneira de observar isso - o arquivo é removido apenas quando osleep
processo é interrompido (rm
apenas remove sua entrada de diretório).Com a estratégia 3, a etapa de mover o novo arquivo para o nome existente remove a entrada de diretório que leva ao conteúdo antigo e cria uma entrada de diretório que leva ao novo conteúdo. Isso é feito em uma operação atômica, portanto, essa estratégia tem uma grande vantagem: se um processo abrir o arquivo a qualquer momento, ele verá o conteúdo antigo ou o novo conteúdo - não há risco de obter conteúdo misto ou o arquivo não existir.
Substituindo Executáveis
Se você tentar a estratégia 1 com um executável em execução no Linux, receberá um erro.
Um "arquivo de texto" significa um arquivo que contém código executável por razões históricas obscuras . O Linux, como muitas outras variantes do unix, se recusa a sobrescrever o código de um programa em execução; algumas variantes do unix permitem isso, causando falhas, a menos que o novo código seja uma modificação muito boa do código antigo.
No Linux, você pode sobrescrever o código de uma biblioteca carregada dinamicamente. É provável que leve a uma falha do programa que o está usando. (Talvez você não consiga observar isso
sleep
porque ele carrega todo o código da biblioteca necessário ao iniciar. Tente um programa mais complexo que faça algo útil depois de dormir, por exemploperl -e 'sleep 9; print lc $ARGV[0]'
).Se um intérprete estiver executando um script, o arquivo de script será aberto normalmente pelo intérprete, portanto, não haverá proteção contra a substituição do script. Alguns intérpretes leem e analisam o script inteiro antes de começarem a executar a primeira linha, outros leem o script conforme necessário. Consulte O que acontece se você editar um script durante a execução? e Como o Linux lida com scripts de shell? para mais detalhes.
As estratégias 2 e 3 também são seguras para os executáveis: embora a execução de executáveis (e bibliotecas carregadas dinamicamente) não sejam arquivos abertos no sentido de ter um descritor de arquivo, eles se comportam de maneira muito semelhante. Enquanto algum programa estiver executando o código, o arquivo permanecerá em disco, mesmo sem uma entrada de diretório.
Atualizando um aplicativo
A maioria dos gerenciadores de pacotes usa a estratégia 3 para substituir arquivos, devido à grande vantagem mencionada acima - a qualquer momento, a abertura do arquivo leva a uma versão válida dele.
Onde as atualizações de aplicativos podem ser interrompidas é que, enquanto a atualização de um arquivo é atômica, a atualização do aplicativo como um todo não ocorre se o aplicativo consistir em vários arquivos (programa, bibliotecas, dados, ...). Considere a seguinte sequência de eventos:
Na etapa 3, a instância em execução da versão antiga do aplicativo está abrindo um arquivo de dados da nova versão. Se isso funciona ou não, depende do aplicativo, de qual arquivo é e de quanto foi modificado.
Após uma atualização, você notará que o programa antigo ainda está em execução. Se você deseja executar a nova versão, precisará sair do programa antigo e executar a nova versão. Os gerenciadores de pacotes geralmente matam e reiniciam daemons em uma atualização, mas deixam os aplicativos do usuário final em paz.
Alguns daemons têm procedimentos especiais para lidar com atualizações sem precisar matar o daemon e aguardar a nova instância reiniciar (o que causa uma interrupção no serviço). Isso é necessário no caso do init , que não pode ser morto; Os sistemas init fornecem uma maneira de solicitar que a instância em execução chame
execve
para se substituir pela nova versão.fonte
unlink
, como você verá mais tarde. Talvez "substitua o nome existente", mas isso ainda é um pouco confuso.A atualização pode ser executada enquanto o programa é executado, mas o programa em execução que você vê é realmente a versão antiga. O binário antigo permanece no disco até você fechar o programa.
Explicação: nos sistemas Linux, um arquivo é apenas um inode, que pode ter vários links para ele. Por exemplo. o que
/bin/bash
você vê é apenas um link parainode 3932163
no meu sistema. Você pode descobrir qual inode vincula algo emitindols --inode /path
no link. Um arquivo (inode) será removido apenas se houver zero links apontando para ele e não estiver em uso por nenhum programa. Quando o gerenciador de pacotes é atualizado, por exemplo./usr/bin/firefox
, ele primeiro desassocia (remove o link físico/usr/bin/firefox
) e depois cria um novo arquivo chamado/usr/bin/firefox
que é um link físico para um inode diferente (aquele que contém a novafirefox
versão). O inode antigo agora está marcado como livre e pode ser reutilizado para armazenar novos dados, mas permanece no disco (os inodes são criados apenas quando você constrói seu sistema de arquivos e nunca são excluídos). No próximo começo defirefox
, o novo será usado.Se você deseja escrever um programa que se atualiza durante a execução, a única solução possível é verificar periodicamente o registro de data e hora de seu próprio arquivo binário e, se for mais recente que o horário de início do programa, recarregue-se.
fonte
apt
trabalho de atualização do Debian ? Posso atualizar qualquer programa em execução sem problemas, incluindoIceweasel
(Firefox
).dpkg
) não substitui arquivos. Em vez disso, os desvincula e coloca um novo com o mesmo nome. Veja a pergunta e resposta à qual vinculei para obter uma explicação.ln
(links físicos). Você pode remover nomes comrm
(desvincular). Na verdade, você não pode excluir diretamente um arquivo, apenas remover seus nomes. Quando um arquivo não tem nomes e, adicionalmente, não está aberto, o kernel o exclui. Um programa em execução possui o arquivo do qual está sendo aberto, portanto, mesmo depois de remover todos os nomes, o arquivo ainda está por aí.Gostaria de saber como aplicativos matadores, como Thunderbird ou Firefox, podem ser atualizados através do gerenciador de pacotes do sistema enquanto eles ainda estão em execução? Bem, posso lhe dizer que isso realmente não funciona bem ... O Firefox quebrou-me bastante se eu o deixasse aberto enquanto uma atualização de pacote estava em execução. Às vezes, eu tinha que matá-lo com força e reiniciá-lo, porque estava tão quebrado que nem conseguia fechá-lo corretamente.
O que acontece com o código antigo enquanto eles estão sendo atualizados? Normalmente, no Linux, um programa é carregado na memória; portanto, o executável em disco não é necessário ou usado enquanto o programa está em execução. Na verdade, você pode até excluir o executável e o programa não deve se importar ... No entanto, alguns programas podem precisar do executável, e certos sistemas operacionais (como o Windows) bloquearão o arquivo executável, impedindo a exclusão ou até renomeando / movendo, enquanto o programa está sendo executado. O Firefox quebra, porque é realmente bastante complexo e usa um monte de arquivos de dados que informam como criar sua GUI (interface do usuário). Durante uma atualização do pacote, esses arquivos são substituídos (atualizados); portanto, quando um executável antigo do Firefox (na memória) tenta usar os novos arquivos da GUI, coisas estranhas podem acontecer ...
O que tenho que fazer quando quero escrever um programa a.out que se atualize enquanto estiver em execução? Já existem muitas respostas para sua pergunta. Confira: /programming/232347/how-should-i-implement-an-auto-updater A propósito, as perguntas sobre programação são melhores no StackOverflow.
fonte