Почему я могу cat / dev?

4485
haboutnnah

Я могу cat /dev, я могу ls /dev, я не могу less /dev. Почему catмне разрешен catэтот каталог, а других нет?

Picture of this behaviour in zsh.

40
@KamilMaciorowski, вот вывод и `neofetch` для вашей информации :) https://i.imgur.com/3azpnDt.png haboutnnah 5 лет назад 0

2 ответа на вопрос

42
nneonneo

Исторически (до V7 UNIX или около 1979 года) readсистемный вызов работал как с файлами, так и с каталогами. readon каталог вернул бы простую структуру данных, которую пользовательская программа проанализировала бы для получения записей каталога. Действительно, lsинструмент V7 сделал именно это - readв каталоге, синтаксический анализ полученной структуры данных, вывод в формате структурированного списка.

Поскольку файловые системы становились все более сложными, эта «простая» структура данных становилась все более сложной, вплоть до того, что readdirбыла добавлена ​​библиотечная функция, чтобы помочь программам анализировать выходные данные read(directory). Различные системы и файловые системы могут иметь разные форматы на диске, что усложняется.

Когда Sun представила сетевую файловую систему (NFS), они хотели полностью абстрагироваться от структуры каталогов на диске. Однако вместо того, чтобы сделать их read(directory)возвращение независимым от платформы представлением каталога, они добавили новый системный вызов getdirents- и запретили readустанавливать сетевые каталоги. Этот системный вызов был быстро адаптирован для работы со всеми каталогами в различных вариантах UNIX, что сделало его стандартным способом получения содержимого каталогов. (История извлечена из https://utcc.utoronto.ca/~cks/space/blog/unix/ReaddirHistory )

Поскольку readdirтеперь это способ чтения каталогов по умолчанию, read(directory)он обычно не реализован (возвращая -EISDIR) в большинстве современных ОС (например, QNX является заметным исключением, которое реализуется readdirкак read(directory)). Тем не менее, с дизайном «виртуальной файловой системы» в большинстве современных ядер, фактически зависит от отдельной файловой системы, работает ли чтение каталога или нет.

И действительно, в macOS devfsфайловая система, лежащая в основе точки /devмонтирования, действительно поддерживает чтение ( https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/bsd/miscfs/devfs/devfs_vnops.c#L629 ) :

static int devfs_read(struct vnop_read_args *ap) { devnode_t * dn_p = VTODN(ap->a_vp);  switch (ap->a_vp->v_type) { case VDIR: { dn_p->dn_access = 1;  return VNOP_READDIR(ap->a_vp, ap->a_uio, 0, NULL, NULL, ap->a_context); 

Это явно вызывается, READDIRесли вы пытаетесь читать /dev(чтение файлов под /devним обрабатывается отдельной функцией - devfsspec_read). Итак, если программа вызывает readсистемный вызов /dev, она будет выполнена успешно и получит список каталогов!

Эта функция, по сути, является пережитком с самых ранних дней UNIX и не затрагивалась в течение очень долгого времени. Часть меня подозревает, что это сохраняется по какой-то причине обратной совместимости, но это может быть так же легко, как тот факт, что никто не заботится о том, чтобы удалить эту функцию, поскольку она на самом деле ничего не вредит.

Вероятно, последний, видя, как он был удален из большинства каталогов. user20574 5 лет назад 0
36
grawity

Меньше просмотрщик текстовых файлов, cat - инструмент для копирования произвольных данных. Поэтому less выполняет свою собственную проверку, чтобы убедиться, что вы не открываете что-то, что будет содержать большие объемы данных или будет вести себя очень странно. С другой стороны, у cat нет такой проверки вообще - если ядро ​​позволяет вам что-то открыть (даже если это канал, устройство или что-то еще хуже), cat прочитает это.

Так почему же ОС позволяет cat открывать каталоги? Традиционно в системах в стиле BSD все каталоги могут быть прочитаны как файлы, и именно так программы будут перечислять каталог в первую очередь: просто интерпретируя структуры директив, хранящиеся на диске.

Позднее эти структуры на диске начали расходиться с директивой, используемой ядром: где ранее каталог представлял собой линейный список, более поздние файловые системы начали использовать хеш-таблицы, B-деревья и так далее. Так что чтение каталогов напрямую стало не простым делом - в ядре появились специальные функции для этого. (Я не уверен, что это было основной причиной, или они были добавлены прежде всего по другим причинам, таким как кеширование.)

Некоторые системы BSD продолжают открывать все каталоги для чтения; Я не знаю, дают ли они вам необработанные данные с диска, или вместо этого они возвращают эмулированный список директив, или позволяют ли они решать драйверу файловой системы.

Так что, возможно, macOS является одной из тех операционных систем, где ядро ​​позволяет это, пока файловая система предоставляет данные. И разница в том, что /devв devfsфайловой системе, которая была написана, чтобы позволить это в первые дни, в то время /как в файловой системе APFS, которая опускала эту функцию как ненужную в наше время.

Отказ от ответственности: я на самом деле не проводил никаких исследований на BSD или MacOS. Я просто обожаю это.

Кажется, это имеет смысл. Существуют ли другие разделы хранилища, которые отличаются от стандартной файловой системы ОС? Я предполагал, что `/ etc` будет, поэтому я использовал это в качестве своего эталона. haboutnnah 5 лет назад 0
Наоборот, обычно / etc это обычная папка, содержащая обычные файлы. Однако могут существовать и другие виртуальные файловые системы - запустите `mount` или` / sbin / mount`, чтобы увидеть, где и где сейчас монтируется. grawity 5 лет назад 2
Ты прав! Смотрите это: https://i.imgur.com/pcVpo1o.png haboutnnah 5 лет назад 0
Это действительно здорово @grawity, https://i.imgur.com/8QuR0FK.png haboutnnah 5 лет назад 0
Что ж, прямое чтение _диска_ - это вполне нормальная операция, потому что диски в любом случае просто имеют плоскую структуру (именно так вы можете создать образ .iso CD). grawity 5 лет назад 0
@ Grawity: Интересно, что хуже :), чем открытие устройства, какие-нибудь вредоносные примеры? ^^ JIV 5 лет назад 0
@haboutnnah Ваш скриншот подтверждает, что `/ dev` является виртуальной файловой системой, использующей драйвер` devfs`, тогда как `/ etc` является частью файловой системы` / `, использующей драйвер` apfs`. Поэтому причина, по которой `cat` будет читать одно, а не другое, заключается в разнице между драйверами` apfs` и `devfs`. kasperd 5 лет назад 6