Os comandos encadeados são atômicos?

8

Se houvesse um processo gravando continuamente em um arquivo, e eu quisesse assumir o controle do arquivo com raiz, eu poderia fazer algo assim:

sudo rm somefile; sudo touch somefile

É possível que o processo anexado seja anexado ao arquivo entre esses dois comandos? Em caso afirmativo, existe uma maneira de garantir que nenhum outro comando seja executado no meio?

Darth Egregious
fonte
4
Isso pode ser um problema XY . Você pode explicar o problema subjacente que você está tentando resolver?
Nate Eldredge
1
@NateEldredge: totalmente não. Eu posso entender por que parece assim, com base em minha hipótese inventada. Nem sequer tem um problema. Apenas curioso.
Darth Egregious
5
O processo provavelmente continuará gravando no arquivo excluído e nem sequer tentará abrir o novo.
usar o seguinte código
Minha suposição no hipotético mostrou-se um pouco errada, mas acho que você pode alterar "anexar" para "abrir" ou "tocar" e ainda faria sentido.
Darth Egregious

Respostas:

12

Uma linha de comando encadeada é basicamente um pequeno script de shell; ele executará o primeiro comando usando o procedimento usual fork + exec, espere que ele saia e execute o segundo da mesma maneira. Entre os dois comandos, há uma quantidade arbitrária de tempo que o shell leva em sua contabilidade e processamento, durante o qual o multiprocessamento comum ocorre e outros processos arbitrários podem fazer outras coisas arbitrárias. Então a resposta é 'não'. (Se você realmente fizer isso, verá que a entrada do diretório somefiledesaparece, mas o próprio arquivo permanece (desde que foi aberto por um processo) até ser fechado. O espaço em disco usado pelo arquivo não será recuperado até que isso aconteça. , o touchcomando criará um novo arquivo não relacionado com o mesmo nome e caminho.)

Se você deseja alterar a propriedade do arquivo para root, faça-o sudo chown root:root somefile(embora não tenha certeza de como isso afetará os processos com uma manipulação de arquivo aberta). Se você deseja destruir o conteúdo atual do arquivo, tente truncate -s 0 somefile(o processo em execução continuará sendo anexado ao arquivo agora vazio). Se for outra coisa, talvez esclareça o que você quer fazer.

Tom Hunt
fonte
Obrigado Tom. Eu não estava tão preocupado com minha situação hipotética. Só estava pensando se é possível fazer algo assim.
Darth Egregious
Em relação à questão geral, não acho que exista realmente uma maneira de garantir atomicidade em um shell script. Você pode usar arquivos de bloqueio para garantir que dois processos de cooperação não se interajam e você pode usar permissões para garantir que um processo arbitrário não possa interferir no seu trabalho. Mas impedir a execução de qualquer outra coisa atrapalhava muito o multiprocessamento do kernel; Eu não acho que o código ring-3 possa fazer isso.
Tom Hunt
Você pode usar bloqueios obrigatórios de arquivos se eles estiverem ativados e disponíveis no seu sistema de arquivos.
roaima 8/09/2015
5
chownA criação de algum arquivo não afetará os processos que possuem um identificador de arquivo para algum arquivo.
PSKocik 08/09/2015
Por exemplo, você pode fazer exec 3>somefile; sudo chmod 0600 somefile; echo hello world >&3; sudo cat somefile; exec 3>&-.
PSKocik 08/09/2015
6

Não. Um rmcomando seguido por um touchcomando não é atômico. Vai demorar muito tempo entre os dois comandos - possivelmente na faixa de milissegundos. Muita coisa pode acontecer durante esse tempo. Se você não tiver sorte, suas credenciais sudo podem até expirar.

Um único programa chamando as chamadas unlinke opendeixaria uma janela muito mais curta para uma corrida, mas isso ainda poderia acontecer.

Uma abordagem mais segura seria criar o novo arquivo com um nome temporário e usar a renamechamada do sistema. "Substituir" um nome com a renamechamada do sistema é garantido como atômico. Isso pode ser alcançado usando touche mv.

Mas um processo que abriu o arquivo antigo para gravação pode continuar gravando nele muito tempo depois de ter sido excluído. Este será o caso de um arquivo excluído usando unlinke um excluído usando rename.

Kasperd
fonte
3

Depois que um processo tem um identificador de arquivo aberto para leitura, não importa o que você faz com a propriedade ou as permissões: o processo pode continuar acessando o arquivo. Você pode até excluir o arquivo e o processo poderá continuar acessando-o através do tratamento de arquivos.

Considere as permissões como um portão de controle para obter um identificador de arquivo.

Se você deseja criar um arquivo atomicamente, em vez de fazer isso:

sudo rm somefile
sudo touch somefile

você pode considerar isso:

sudo touch anotherfile
sudo perl -e "rename 'anotherfile', 'somefile'"

que substituirá atomicamente somefilepor anotherfile. (Eu preferiria usar, mv -fmas não consigo encontrar uma instrução que garanta isso de chamada de rename(2)sistema.


Talvez você possa atualizar sua pergunta para explicar o que você quer dizer com "assuma o controle do arquivo". Você pode ter um problema XY aqui.

roaima
fonte
Use mv -fpara receber uma rename(2)chamada do sistema. Você está certo que lnnão, porque sempre usa a link(2)chamada do sistema, que não pode substituir atomicamente. ln -fapenas faz unlink(2)no alvo primeiro.
Peter Cordes
@ PeterCordes ah sim, claro, obrigado. Eu tinha lnno cérebro. Eu não tinha certeza de como obter rename(2)a garantia de ser envolvido e era tarde demais para ir cavar ainda mais
roaima
O POSIX garante que mv"deve executar ações equivalentes a" rename(old, new). pubs.opengroup.org/onlinepubs/9699919799/utilities/mv.html . mv -fage como mv -ise o destino não fosse gravável, mas não é como cp -fou ln -fonde será desvinculado primeiro.
Peter Cordes
2

Não mas

sudo rm somefile; sudo touch somefile

é seguro na maioria das situações.

A maioria dos processos abre arquivos e, em seguida, usa o descritor de arquivo adquirido para acessar o conteúdo do arquivo.

Se um processo abrir algum arquivo, em sh:

 exec 3>somefile

Em seguida, outro processo é livre para desvincular (= remover) algum arquivo e o editor de arquivo no qual o arquivo foi aberto pelo primeiro processo (3 neste caso) continuará a se referir ao conteúdo original do arquivo, que agora é um arquivo no limbo.

sudo touch somefile

criará um novo arquivo de arquivo não relacionado e todos os processos que tiveram o arquivo de arquivo antigo aberto e agora estão usando apenas um editor de arquivo para se referir a ele não serão afetados porque estão se referindo a um arquivo diferente - que agora está no limbo.

Se um processo não raiz tentar se referir a algum arquivo por nome, ele receberá um erro EPERM, porque o novo arquivo é propriedade da raiz.

Se você deseja impedir que vários processos sob o mesmo usuário (por exemplo, root) corrompam um arquivo, o linux possui um bloqueio obrigatório e consultivo. Você pode usar o flockcomando em scripts de shell para bloqueio de arquivo consultivo (consulte a página de manual para obter mais informações).

PSkocik
fonte