mv un fichier dans / dev / null interrompt dev / null

25

Si je le fais: en touch file; mv file /dev/nulltant que root, /dev/nulldisparaît. ls -lad /dev/nullrésulte en aucun fichier ou répertoire. Cela casse les applications qui dépendent de /dev/nullSSH similaires et peuvent être résolues en faisant mknod /dev/null c 1 3; chmod 666 /dev/null. Pourquoi le déplacement d'un fichier normal vers ce fichier spécial entraîne-t-il la disparition de /dev/null?

Pour clarifier, c'était à des fins de test, et je comprends comment fonctionne la mvcommande. Ce que je suis curieux de savoir, c'est pourquoi ls -la /dev/nullavant de le remplacer par un fichier normal, la sortie attendue est affichée, mais ensuite cela montre que cela /dev/nulln'existe pas même si un fichier aurait été créé via la mvcommande d' origine et que la commande de fichier affiche du texte ASCII. Je pense que cela doit être une combinaison du lscomportement de la commande en conjonction avec devfsquand un fichier non spécial remplace un fichier caractère / spécial. C'est sur Mac OS X, les comportements peuvent varier sur d'autres OS.

Gregg Leventhal
la source
44
Ne plaisante pas /dev/null.
devnull
7
ainsi dit @devnull
Braiam
3
La bonne façon de supprimer des fichiers est la rmcommande.
casey
1
On dirait que c'est la racine de votre problème, OSX devfsest drôle avec les fichiers normaux. Étrange, cependant, vous n'avez pas obtenu d'erreur mv. Que diriez-vous de cette façon touch testfile; mv testfile /dev:?
Graeme
3
@Gregg, mvne peut être atomique que sur le même système de fichiers.
Graeme

Réponses:

16

En regardant le code source de 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);
}

Lors du premier passage dans la boucle while, open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)échouera avec EEXIST. Puis /dev/nullsera dissocié et la boucle répétée. Mais comme vous l'avez souligné dans votre commentaire, les fichiers normaux ne peuvent pas être créés /dev, donc lors du prochain passage dans la boucle, cela open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)échouera toujours.

Je déposerais un rapport de bogue avec Apple. Le mvcode source est pratiquement inchangé par rapport à la version FreeBSD, mais comme le devfs d'OSX a ce comportement non-POSIX avec les fichiers normaux, Apple devrait corriger leur mv.

Mark Plotnick
la source
1
Je donne cette meilleure réponse en ce moment pour fournir le code source et reconnaître cela comme un bug, ce à quoi je voulais en venir.
Gregg Leventhal
12

Le déplacement d'un fichier vers l'emplacement d'un fichier déjà existant remplace le fichier existant. Dans ce cas, le /dev/nullfichier de périphérique est remplacé, tout comme n'importe quel fichier normal. Pour éviter cela, utilisez l' option -i(interactive, avertit avant d'écraser) ou -n(pas de clober) pour mv.

/dev/nullne remplit sa fonction spéciale que comme un ensemble de bits, puis l'appareil est ouvert tel quel. Par exemple, lorsque l' >opérateur shell est utilisé, le fichier est ouvert puis tronqué (non supprimé et remplacé, ce qui peut être ce que vous attendiez). Comme mentionné par casey, la bonne façon de supprimer un fichier est avec rmou même avec unlink.

Graeme
la source
Voir mes commentaires à terdon.
Gregg Leventhal
Compris, le -d n'était pas nécessaire, c'est juste une mauvaise habitude mais le fichier devrait toujours apparaître dans la sortie ls, il ne devrait pas apparaître comme inexistant.
Gregg Leventhal
@Graeme - bienvenue à 3K, beau travail!
slm
10

Umm, parce que vous écrasez le fichier spécial avec un fichier normal? À quoi vous attendiez-vous? dev/nulln'est pas un répertoire, c'est un fichier pointant vers un nullpériphérique. Lorsque vous avez mvquelque chose, vous supprimez l'original et le remplacez par ce que vous avez déplacé:

$ file /dev/null 
/dev/null: character special 
$ sudo mv file /dev/null 
$ file /dev/null 
/dev/null: ASCII text
terdon
la source
2
Mais je dis que / dev / null était affiché comme manquant lors de l'exécution d'un ls -lad / dev / null. Ce doit être quelque chose de spécifique aux devfs, c'est ce que je voulais savoir.
Gregg Leventhal
Si je mv file / dev / null alors / dev / null doit contenir quel fichier contient mais existe toujours. Je veux savoir pourquoi cela n'a pas permis de trouver / dev / null dans un ls.
Gregg Leventhal
Certes, je fais cela sur un Mac, donc cela pourrait être légèrement différent, mais je ne m'attendais pas à ce que le fichier s'affiche comme manquant, je m'attendais à ce qu'il s'affiche comme modifié dans le fichier source.
Gregg Leventhal
@GreggLeventhal oui, ce doit être une chose OSX ou BSD (veuillez éditer votre Q et spécifier votre OS). Sur mon Linux, je peux encore voir /dev/null, c'est juste devenu le fichier que j'ai déplacé.
terdon