MV файл в / dev / null разрывы dev / null

25

Если я делаю: touch file; mv file /dev/nullкак root, /dev/nullисчезает. ls -lad /dev/nullв результате нет такого файла или каталога. Это ломает приложения, которые зависят от /dev/nullподобного SSH и могут быть решены путем mknod /dev/null c 1 3; chmod 666 /dev/null. Почему перемещение обычного файла в этот специальный файл приводит к исчезновению /dev/null?

Чтобы уточнить, это было в целях тестирования, и я понимаю, как mvработает команда. Что меня интересует, так это то, почему ls -la /dev/nullперед заменой его обычным файлом отображается ожидаемый результат, но впоследствии он показывает, что /dev/nullего не существует, даже если файл был предположительно создан с помощью исходной mvкоманды, а команда file показывает текст ASCII. Я думаю, что это должно быть сочетание lsповедения команды в сочетании с тем, devfsкогда не специальный файл заменяет символ / специальный файл. Это на Mac OS X, поведение может отличаться на других ОС.

Грегг Левенталь
источник
44
Не связывайтесь с /dev/null.
devnull
7
так говорит @devnull
Брайам
3
Правильный способ удаления файлов - это rmкоманда.
Кейси
1
Похоже, это корень вашей проблемы, OSX devfsсмешно с обычными файлами. Странно, вы не получили ошибку, mvхотя. Как об этом пути: touch testfile; mv testfile /dev?
Грэм
3
@Gregg, mvможет быть атомарным только в одной файловой системе.
Грэм

Ответы:

16

Глядя на исходный код для 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);
}

При первом прохождении цикла while open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)произойдет сбой EEXIST. Затем /dev/nullбудет отключен, и цикл повторяется. Но, как вы указали в своем комментарии, обычные файлы не могут быть созданы /dev, поэтому при следующем прохождении цикла open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)все равно произойдет сбой.

Я бы подал отчет об ошибке в Apple. mvИсходный код в основном не отличается от версии FreeBSD, а потому , что DevFS OSX имеет такое поведение не-POSIX с обычными файлами, Apple должна исправить их mv.

Марк Плотник
источник
1
Сейчас я даю этот лучший ответ за предоставление исходного кода и признание его как ошибки, к чему я и стремился.
Грегг Левенталь
12

Перемещение файла в местоположение уже существующего файла заменяет существующий файл. В этом случае /dev/nullфайл устройства заменяется, как и любой обычный файл. Чтобы избежать этого, используйте параметр -i(интерактивный, предупреждает перед перезаписью) или -n(без расширения) для mv.

/dev/nullтолько выполняет свою специальную функцию в качестве набора битов, затем устройство открывается как есть. Например, когда используется >оператор оболочки, файл открывается, затем усекается (не удаляется замененный, что может быть тем, что вы ожидали). Как упомянул Кейси, правильный способ удаления файла - с rmили даже с unlink.

Graeme
источник
Смотрите мои комментарии к Тердону.
Грегг Левенталь
Понятно, что -d не нужен, это просто плохая привычка, однако файл все равно должен отображаться в выводе ls, он не должен отображаться как несуществующий.
Грегг Левенталь
@Graeme - добро пожаловать в 3K, отличная работа!
SLM
10

Хм, потому что вы перезаписали специальный файл обычным? Чего ты ожидал? dev/nullэто не каталог, это файл, указывающий на nullустройство. Когда вы mvчто-то делаете, вы удаляете оригинал и заменяете его тем, что вы переместили:

$ file /dev/null 
/dev/null: character special 
$ sudo mv file /dev/null 
$ file /dev/null 
/dev/null: ASCII text
Тердон
источник
2
Но я говорю, что / dev / null показывался как отсутствующий при запуске ls -lad / dev / null. Это должно быть что-то конкретное для devfs, это то, о чем я хотел знать.
Грегг Левенталь
Если я mv файл / dev / null, то / dev / null должен содержать, какой файл содержался, но все еще существует. Я хочу знать, почему это привело к тому, что / dev / null не было найдено в ls.
Грегг Левенталь
Конечно, я делаю это на Mac, поэтому он может немного отличаться, но я не ожидал, что файл будет отображаться как отсутствующий, я только ожидал, что он будет отображаться как измененный в исходном файле.
Грегг Левенталь
@GreggLeventhal Да, это должно быть OSX или BSD (пожалуйста, отредактируйте свой Q и укажите свою ОС). В моем Linux я все еще вижу /dev/null, это просто файл, который я переместил.
Terdon