mv um arquivo para / dev / null quebra dev / null

25

Se eu fizer isso: touch file; mv file /dev/null como root, /dev/null desaparecerá. ls -lad /dev/null resulta em nenhum arquivo ou diretório desse tipo. Isso quebra os aplicativos que dependem de /dev/null , como o SSH, e podem ser resolvidos com 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 entendo como o comando mv funciona. O que eu estou curioso sobre é por que ls -la /dev/null antes de substituí-lo com um arquivo regular mostra a saída esperada, mas depois ele mostra que /dev/null não existe mesmo que um arquivo tenha sido criado pelo comando mv original e o arquivo comando mostra texto ASCII. Eu acho que isso deve ser uma combinação do comportamento do comando ls em conjunto com devfs quando um arquivo não especial substitui um caractere / arquivo especial. Isso é no Mac OS X, os comportamentos podem variar em outros sistemas operacionais.

    
por Gregg Leventhal 03.03.2014 / 18:14

3 respostas

16

Observando o código-fonte do mv, link :

/*
 * 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/null será desvinculado e o loop será repetido. Mas como você apontou em seu comentário, arquivos regulares não podem ser criados em /dev , então na próxima passagem pelo loop, open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0) ainda irá falhar.

Eu arquivaria um relatório de bug com a Apple. O código-fonte mv está 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 corrigir seu mv .

    
por 04.03.2014 / 14:03
12

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

/dev/null executa apenas sua função especial como um depósito de bits, em seguida, o dispositivo é aberto como está. Por exemplo, quando o operador > shell é usado, o arquivo é aberto e, em seguida, truncado (não removido, substituído, que pode ser o que você esperava). Como mencionado por casey, a maneira correta de remover um arquivo é com rm ou mesmo com unlink .

    
por 03.03.2014 / 18:19
10

Umm, porque você sobrescreve o arquivo especial com um normal? O que você esperava que acontecesse? dev/null não é um diretório, é um arquivo que aponta para um dispositivo null . Quando você mv algo, você excluir o original e substituí-lo com o que você se mudou:

$ file /dev/null 
/dev/null: character special 
$ sudo mv file /dev/null 
$ file /dev/null 
/dev/null: ASCII text
    
por 03.03.2014 / 18:20