mv um arquivo para / dev / null interrompe dev / null

25

Se eu fizer: touch file; mv file /dev/nullcomo raiz, /dev/nulldesaparece. ls -lad /dev/nullresulta em nenhum arquivo ou diretório. Isso interrompe aplicativos que dependem do /dev/nullSSH e podem ser resolvidos fazendo isso mknod /dev/null c 1 3; chmod 666 /dev/null. Por que mover um arquivo regular para esse arquivo especial resulta no desaparecimento de /dev/null?

Para esclarecer, isso foi feito para fins de teste e eu entendo como o mvcomando funciona. O que me interessa é o motivo pelo qual, ls -la /dev/nullantes de substituí-lo por um arquivo regular, mostra a saída esperada, mas depois mostra que /dev/nullnão existe, mesmo que um arquivo tenha sido supostamente criado por meio do mvcomando original e o comando file mostre Texto ASCII. Eu acho que isso deve ser uma combinação do lscomportamento do comando em conjunto com devfsquando um arquivo não especial substitui um caractere / arquivo especial. Isso ocorre no Mac OS X, os comportamentos podem variar em outros sistemas operacionais.

Gregg Leventhal
fonte
44
Não mexa com /dev/null.
Devnull 3/03/14
7
assim diz @devnull
Braiam
3
A maneira correta de excluir arquivos é o rmcomando
casey
11
Parece que essa é a raiz do seu problema, o OSX devfsé engraçado com arquivos normais. Estranho, você não recebeu um erro mv. Que tal assim touch testfile; mv testfile /dev:?
Graeme
3
@ Gregg, mvsó pode ser atômico no mesmo sistema de arquivos.
Graeme

Respostas:

16

Examinando o código fonte do mv, http://www.opensource.apple.com/source/file_cmds/file_cmds-220.7/mv/mv.c :

/*
 * If rename fails because we're trying to cross devices, and
 * it's a regular file, do the copy internally; otherwise, use
 * cp and rm.
 */
if (lstat(from, &sb)) {
    warn("%s", from);
    return (1);
}
return (S_ISREG(sb.st_mode) ?
    fastcopy(from, to, &sb) : copy(from, to));

...

int
fastcopy(char *from, char *to, struct stat *sbp)
{
...
while ((to_fd =
    open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)) < 0) {
        if (errno == EEXIST && unlink(to) == 0)
            continue;
        warn("%s", to);
        (void)close(from_fd);
        return (1);
}

Na primeira passagem pelo loop while, open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)falhará com EEXIST. Então /dev/nullserá desvinculado, e o loop será repetido. Mas, como você apontou no seu comentário, os arquivos regulares não podem ser criados /dev, portanto, na próxima passagem pelo loop, open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)ainda falhará.

Eu apresentaria um relatório de bug na Apple. O mvcódigo fonte é praticamente inalterado em relação à versão do FreeBSD, mas como o devfs do OSX tem esse comportamento não POSIX com arquivos regulares, a Apple deve corrigi-los mv.

Mark Plotnick
fonte
11
Estou dando a melhor resposta agora por fornecer código fonte e reconhecê-lo como um bug, que é o que eu estava dirigindo.
precisa
12

Mover um arquivo para o local de um arquivo já existente substitui o arquivo existente. Nesse caso, o /dev/nullarquivo do dispositivo é substituído, assim como qualquer arquivo normal. Para evitar isso, use a opção -i(interativo, avisa antes de substituir) ou -n(sem clober) para mv.

/dev/nullsomente executa sua função especial como um balde de bits, o dispositivo é aberto como está. Por exemplo, quando o >operador shell é usado, o arquivo é aberto e truncado (não removido e substituído, que pode ser o que você esperava). Como mencionado por Casey, a maneira correta de remover um arquivo é com rmou mesmo com unlink.

Graeme
fonte
Veja meus comentários para Terdon.
Gregg Leventhal
Entendido, o -d era desnecessário, isso é apenas um mau hábito; no entanto, o arquivo ainda deve aparecer na saída ls, não deve aparecer como inexistente.
Gregg Leventhal
@Graeme - bem-vindo ao 3K, bom trabalho!
Slm
10

Hum, porque você substituiu o arquivo especial pelo normal? O que você esperava que fosse acontecer? dev/nullnão é um diretório, é um arquivo apontando para um nulldispositivo. Quando você faz mvalgo, exclui o original e o substitui pelo que você moveu:

$ file /dev/null 
/dev/null: character special 
$ sudo mv file /dev/null 
$ file /dev/null 
/dev/null: ASCII text
terdon
fonte
2
Mas estou dizendo que / dev / null estava aparecendo como ausente ao executar um ls -lad / dev / null. Isso deve ser algo específico para os devfs, que é o que eu queria saber.
Gregg Leventhal
Se eu mv arquivo / dev / null, / dev / null deve conter o arquivo contido, mas ainda existe. Quero saber por que isso fez com que / dev / null não fosse encontrado em um ls.
Gregg Leventhal
Concedido, eu estou fazendo isso em um Mac, portanto, pode ser um pouco diferente, mas não esperava que o arquivo fosse exibido como ausente, só esperava que fosse exibido como alterado no arquivo de origem.
Gregg Leventhal
@GreggLeventhal sim, deve ser uma coisa OSX ou BSD (edite seu Q e especifique seu sistema operacional). No meu Linux ainda posso ver /dev/null, tornou-se o arquivo que mudei.
terdon