Os comandos encadeados são atômicos?

7

Se houvesse um processo gravando continuamente em um arquivo e eu quisesse controlar o arquivo com o root, poderia fazer algo assim:

sudo rm somefile; sudo touch somefile

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

    
por Darth Egregious 08.09.2015 / 17:32

4 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 de diretório para somefile desaparece, mas o arquivo em si permanece (desde que é aberto por um processo) até que seja fechado. O espaço em disco usado pelo arquivo não será recuperado até que Enquanto isso, o comando touch criará um novo arquivo não relacionado com o mesmo nome e caminho.

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

    
por 08.09.2015 / 17:36
6

Não. Um comando rm seguido por um comando touch não é atômico. Será um longo tempo entre os dois comandos - possivelmente no intervalo de milissegundos. Muita coisa pode acontecer durante esse tempo. Se você tiver azar, suas credenciais sudo podem até expirar.

Um único programa chamando as chamadas unlink e open deixaria uma janela muito menor 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 chamada do sistema rename . "Sobrescrever" um nome com a chamada do sistema rename é garantido como atômico. Isso pode ser feito usando touch e mv .

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

    
por 09.09.2015 / 00:07
3

Quando um processo tiver 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 filehandle.

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

Se você deseja criar um arquivo atomicamente, então, 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 somefile por anotherfile . (Eu preferiria usar mv -f , mas não consigo encontrar uma declaração que garanta que isso chame a chamada do sistema rename(2) .

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

    
por 08.09.2015 / 17:57
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) somefile e o filedescriptor no qual somefile foi aberto pelo primeiro processo (3 neste caso) continuará a se referir ao conteúdo original de algum arquivo, que agora é um arquivo em limbo.

sudo touch somefile

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

Se um processo não-raiz tentar referenciar algum arquivo pelo nome, ele receberá um erro EPERM, porque o novo arquivo é de propriedade da raiz.

Se você quiser impedir que vários processos do mesmo usuário (por exemplo, root) danifiquem um arquivo, o linux tem bloqueio de arquivo obrigatório e consultivo. Você pode usar o comando flock em shell scripts para bloqueio de arquivo consultivo (consulte a manpage para obter mais informações).

    
por 08.09.2015 / 18:22

Tags