Wenn Sie eine Datei nach / dev / null verschieben, wird dev / null unterbrochen

25

Wenn ich das tue: touch file; mv file /dev/nullals root, /dev/nullverschwindet. ls -lad /dev/nullführt zu keiner solchen Datei oder keinem solchen Verzeichnis. Dies unterbricht Anwendungen, die von /dev/nullSSH abhängen und durch Ausführen von gelöst werden können mknod /dev/null c 1 3; chmod 666 /dev/null. Warum führt das Verschieben einer regulären Datei in diese spezielle Datei zum Verschwinden von /dev/null?

Zur Verdeutlichung diente dies zu Testzwecken, und ich verstehe, wie der mvBefehl funktioniert. Ich bin gespannt, warum ls -la /dev/nullvor dem Ersetzen durch eine reguläre Datei die erwartete Ausgabe angezeigt wird. Danach wird jedoch angezeigt, dass /dev/nulldiese nicht vorhanden ist, obwohl eine Datei angeblich über den ursprünglichen mvBefehl erstellt wurde und der Dateibefehl ASCII-Text anzeigt. Ich denke, dies muss eine Kombination des lsBefehlsverhaltens sein, devfswenn eine nicht spezielle Datei ein Zeichen / eine spezielle Datei ersetzt. Dies ist unter Mac OS X der Fall. Das Verhalten kann unter anderen Betriebssystemen variieren.

Gregg Leventhal
quelle
44
Leg dich nicht an /dev/null.
3.
7
so sagt @devnull
Braiam
3
Der richtige Weg, um Dateien zu löschen, ist der rmBefehl.
Casey
1
Anscheinend ist das die Wurzel Ihres Problems. OSX devfsist witzig über normale Dateien. Seltsamerweise haben Sie keinen Fehler bekommen mv. Wie wäre es auf diese Weise touch testfile; mv testfile /dev:?
Graeme
3
@ Gregg, mvkann nur auf demselben Dateisystem atomar sein.
Graeme

Antworten:

16

Den Quellcode für mv finden Sie unter 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);
}

Beim ersten Durchlauf der while-Schleife open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)schlägt EEXIST fehl. Dann /dev/nullwird die Verbindung getrennt und die Schleife wiederholt. Wie Sie in Ihrem Kommentar bereits erwähnt haben, können keine regulären Dateien erstellt werden /dev, sodass der nächste Durchlauf der Schleife open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)weiterhin fehlschlagen wird.

Ich würde einen Fehlerbericht bei Apple einreichen. Der mvQuellcode ist größtenteils unverändert gegenüber der FreeBSD-Version, aber da OSXs devfs dieses Nicht-POSIX-Verhalten bei regulären Dateien aufweist, sollte Apple das Problem beheben mv.

Mark Plotnick
quelle
1
Ich gebe jetzt die beste Antwort, weil ich Quellcode zur Verfügung gestellt und dies als Fehler eingestuft habe.
Gregg Leventhal
12

Das Verschieben einer Datei an den Speicherort einer bereits vorhandenen Datei ersetzt die vorhandene Datei. In diesem Fall wird die /dev/nullGerätedatei wie jede normale Datei ersetzt. Um dies zu vermeiden, verwenden Sie die Option -i(interaktiv, warnt vor dem Überschreiben) oder -n(kein Clober) für mv.

/dev/nullErfüllt seine spezielle Funktion als Bit-Bucket erst dann, wenn das Gerät so wie es ist geöffnet wird. Wenn beispielsweise der >Shell-Operator verwendet wird, wird die Datei geöffnet und dann abgeschnitten (nicht entfernt und ersetzt, was möglicherweise Ihren Erwartungen entspricht). Wie von casey erwähnt, ist der richtige Weg, eine Datei zu entfernen, mit rmoder sogar mit unlink.

Graeme
quelle
Siehe meine Kommentare zu terdon.
Gregg Leventhal
Verstanden, die -d wurde nicht benötigt, das ist nur eine schlechte Angewohnheit, aber die Datei sollte immer noch in der ls-Ausgabe angezeigt werden, sollte nicht als nicht vorhanden angezeigt werden.
Gregg Leventhal
@Graeme - Willkommen bei 3K, gute Arbeit!
SLM
10

Ähm, hast du denn die spezielle Datei mit der normalen überschrieben? Was hast du erwartet? dev/nullist kein Verzeichnis, sondern eine Datei, die auf ein nullGerät verweist . Wenn Sie mvetwas daran ändern, löschen Sie das Original und ersetzen es durch das, was Sie verschoben haben:

$ file /dev/null 
/dev/null: character special 
$ sudo mv file /dev/null 
$ file /dev/null 
/dev/null: ASCII text
terdon
quelle
2
Aber ich sage, dass / dev / null als fehlend angezeigt wurde, als ein ls -lad / dev / null ausgeführt wurde. Das muss etwas spezielles für die Entwickler sein, das ist, was ich wissen wollte.
Gregg Leventhal
Wenn ich die Datei / dev / null mv, dann sollte / dev / null enthalten, welche Datei enthalten, aber noch vorhanden ist. Ich möchte wissen, warum dies dazu führte, dass / dev / null in einem ls nicht gefunden wurde.
Gregg Leventhal
Zugegeben, ich mache das auf einem Mac, es könnte also etwas anders sein, aber ich habe nicht erwartet, dass die Datei als fehlend angezeigt wird. Ich habe nur erwartet, dass sie als in der Quelldatei geändert angezeigt wird.
Gregg Leventhal
@ GreggLeventhal Ja, es muss ein OSX- oder BSD-Ding sein (bitte bearbeite dein Q und spezifiziere dein Betriebssystem). Auf meinem Linux sehe ich immer noch /dev/null, dass es nur die Datei ist, die ich verschoben habe.
Terdon