plik mv do / dev / null przerywa dev / null


25

Jeśli zrobię: touch file; mv file /dev/nulljako root /dev/nullznika. ls -lad /dev/nullpowoduje brak takiego pliku lub katalogu. To łamie aplikacje, które zależą od /dev/nullSSH i można je rozwiązać przez wykonanie mknod /dev/null c 1 3; chmod 666 /dev/null. Dlaczego przeniesienie zwykłego pliku do tego pliku specjalnego powoduje jego zniknięcie /dev/null?

Aby to wyjaśnić, było to w celach testowych i rozumiem, jak mvdziała polecenie. Ciekawe, dlaczego ls -la /dev/nullprzed zastąpieniem go zwykłym plikiem wyświetla oczekiwane dane wyjściowe, ale potem pokazuje, że /dev/nullnie istnieje, mimo że plik został rzekomo utworzony za pomocą oryginalnego mvpolecenia, a polecenie pliku pokazuje tekst ASCII. Myślę, że musi to być kombinacja lszachowania polecenia w połączeniu z sytuacją, devfsgdy plik niespecjalny zastępuje plik znakowy / specjalny. Dotyczy to Mac OS X, zachowania mogą się różnić w innych systemach operacyjnych.


44
Nie zadzieraj z /dev/null.
devnull

7
tak mówi @devnull
Braiam

3
Właściwym sposobem usuwania plików jest rmpolecenie.
Casey

1
Wygląda na to, że to jest przyczyna twojego problemu, OSX devfsjest zabawny z normalnymi plikami. Dziwne, że nie dostałeś jednak błędu mv. Co powiesz na ten sposób touch testfile; mv testfile /dev:?
Graeme

3
@Gregg, mvmoże być atomowy tylko w tym samym systemie plików.
Graeme

Odpowiedzi:


16

Patrząc na kod źródłowy 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);
}

W pierwszym przejściu przez pętlę while open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)zakończy się niepowodzeniem z EEXIST. Następnie /dev/nullzostanie odłączony, a pętla powtórzona. Ale, jak zauważyłeś w swoim komentarzu, nie można utworzyć zwykłych plików /dev, więc przy następnym przejściu przez pętlę open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)nadal zawiedzie.

Złożyłbym raport o błędzie w Apple. mvKod źródłowy jest w większości niezmienione od wersji FreeBSD, ale ponieważ devfs OSX zawiera takie zachowanie nie-POSIX ze zwykłych plików, Apple powinno naprawić swoje mv.


1
Podaję teraz najlepszą odpowiedź za udostępnienie kodu źródłowego i uznanie go za błąd, do którego właśnie dążyłem.
Gregg Leventhal

12

Przeniesienie pliku do lokalizacji już istniejącego pliku zastępuje istniejący plik. W takim przypadku /dev/nullplik urządzenia jest zastępowany, tak jak każdy normalny plik. Aby tego uniknąć, użyj opcji -i(interaktywne, ostrzega przed nadpisaniem) lub -n(bez wyraźnego) dla mv.

/dev/nullwykonuje swoją specjalną funkcję tylko jako wiadro bitów, a następnie urządzenie jest otwierane w takim stanie, w jakim jest. Na przykład, gdy >używany jest operator powłoki, plik jest otwierany, a następnie obcinany (nie usuwany zastępowany, co może być tym, czego oczekiwano). Jak wspomniano przez Casey, poprawnym sposobem na usunięcie pliku jest użycie rmlub nawet użycie unlink.


Zobacz moje komentarze do terdon.
Gregg Leventhal

Zrozumiałe, że -d było niepotrzebne, to po prostu zły nawyk, jednak plik powinien nadal pojawiać się w wyjściu ls, nie powinien być wyświetlany jako nieistniejący.
Gregg Leventhal

@Graeme - witamy w 3K, niezła robota!
slm

10

Umm, ponieważ nadpisujesz specjalny plik normalnym? Czego się spodziewałeś? dev/nullnie jest katalogiem, to plik wskazujący nullurządzenie. Kiedy mvcoś do niego chcesz, usuwasz oryginał i zastępujesz go tym, co przeniosłeś:

$ file /dev/null 
/dev/null: character special 
$ sudo mv file /dev/null 
$ file /dev/null 
/dev/null: ASCII text

2
Ale mówię, że / dev / null był wyświetlany jako brakujący podczas uruchamiania ls -lad / dev / null. To musi być coś specyficznego dla devfs, o tym chciałem wiedzieć.
Gregg Leventhal

Jeśli mam plik mv / dev / null, to / dev / null powinien zawierać to, co plik zawiera, ale nadal istnieje. Chcę wiedzieć, dlaczego to spowodowało, że / dev / null nie został znaleziony w ls.
Gregg Leventhal

To prawda, robię to na komputerze Mac, więc może być nieco inny, ale nie spodziewałem się, że plik będzie wyświetlany jako brakujący, oczekiwałem tylko, że będzie wyświetlany jako zmieniony do pliku źródłowego.
Gregg Leventhal

@GreggLeventhal tak, musi to być OSX lub BSD (edytuj swoje Q i określ swój system operacyjny). W moim systemie Linux nadal widzę /dev/null, że to po prostu plik, który przeniosłem.
terdon
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.