Dlaczego mogę cat / dev?

41

Mogę cat /dev, mogę ls /dev, nie mogę less /dev. Dlaczego catpozwala mi catten katalog, ale nie ma innych katalogów?

Obraz tego zachowania w Zsh.

haboutnnah
źródło
@KamilMaciorowski, oto wynik i neofetchdla twojej informacji :) i.imgur.com/3azpnDt.png
haboutnnah

Odpowiedzi:

43

Historycznie (do V7 UNIX lub około 1979 r.) readWywołanie systemowe działało zarówno na plikach, jak i katalogach. readw katalogu zwróci prostą strukturę danych, którą program użytkownika przeanalizuje w celu uzyskania pozycji katalogu. Rzeczywiście, lsnarzędzie V7 właśnie to zrobiło - readw katalogu parsuje wynikową strukturę danych, wyprowadza w uporządkowanym formacie listy.

Ponieważ systemy plików stały się bardziej złożone, ta „prosta” struktura danych stała się bardziej skomplikowana, do tego stopnia, że ​​dodano readdirfunkcję biblioteki, aby pomóc programom w analizie danych wyjściowych read(directory). Różne systemy i systemy plików mogą mieć różne formaty na dysku, co się komplikuje.

Kiedy Sun wprowadził system plików NFS, chciał całkowicie wyodrębnić strukturę katalogów na dysku. Zamiast jednak read(directory)zwracać niezależną od platformy reprezentację katalogu, dodali nowe wywołanie systemowe getdirents- i zbanowali readw katalogach podłączonych do sieci. To wywołanie systemowe zostało szybko przystosowane do pracy we wszystkich katalogach w różnych wersjach UNIX, dzięki czemu jest to domyślny sposób uzyskiwania zawartości katalogów. (Historia pobrana z https://utcc.utoronto.ca/~cks/space/blog/unix/ReaddirHistory )

Ponieważ readdirjest to teraz domyślny sposób odczytywania katalogów, read(directory)zwykle nie jest implementowany (zwraca -EISDIR) w większości nowoczesnych systemów operacyjnych (na przykład QNX jest godnym uwagi wyjątkiem, który implementuje readdirjako read(directory)). Jednak dzięki projektowi „wirtualnego systemu plików” w większości współczesnych jąder, to od systemu plików zależy, czy czytanie katalogu działa, czy nie.

I rzeczywiście, w systemie macOS, devfssystem plików leżący u podstaw /devmountpoint naprawdę obsługuje czytanie ( 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);

Wywołuje to jawnie, READDIRjeśli próbujesz czytać /dev(odczytywanie plików /devjest obsługiwane przez osobną funkcję - devfsspec_read). Tak więc, jeśli program wywoła readwywołanie systemowe /dev, powiedzie się i uzyska listę katalogów!

Jest to w rzeczywistości funkcja, która jest zapamiętywaniem od bardzo wczesnych dni UNIX-a i nie była dotykana od bardzo dawna. Część mnie podejrzewa, że ​​jest to utrzymywane z jakiegoś powodu wstecznej kompatybilności, ale równie dobrze może to być fakt, że nikomu nie zależy na usunięciu tej funkcji, ponieważ tak naprawdę nic nie rani.

nneonneo
źródło
Prawdopodobnie ten drugi, ponieważ został usunięty z większości katalogów.
user20574,
36

Less to przeglądarka plików tekstowych, cat to narzędzie do kopiowania dowolnych danych. Więc mniej wykonuje własne sprawdzanie, aby upewnić się, że nie otwierasz czegoś, co będzie zawierało ogromne ilości danych lub zachowa się bardzo dziwnie. Z drugiej strony, kot w ogóle nie ma takiego sprawdzania - jeśli jądro pozwala ci coś otworzyć (nawet jeśli jest to potok, urządzenie lub coś gorszego), kot to przeczyta.

Dlaczego system operacyjny pozwala cat otwierać katalogi? Tradycyjnie w systemach typu BSD wszystkie katalogi mogły być odczytywane jako pliki, i w ten sposób programy umieszczałyby katalog na pierwszym miejscu: po prostu interpretując bezpośrednie struktury przechowywane na dysku.

Później te struktury na dysku zaczęły odbiegać od direntu używanego przez jądro: gdzie wcześniej katalog był listą liniową, później systemy plików zaczęły używać tabel hashtable, B-drzewek i tak dalej. Czytanie katalogów bezpośrednio nie było już tak proste - jądro ma do tego dedykowane funkcje. (Nie jestem pewien, czy to był główny powód, czy też zostały dodane głównie z innych powodów, takich jak buforowanie).

Niektóre systemy BSD pozwalają nadal otwierać wszystkie katalogi do czytania; Nie wiem, czy dają ci surowe dane z dysku, czy zamiast tego zwracają emulowaną listę bezpośrednio, czy też decydują sterownik systemu plików.

Być może macOS jest jednym z tych systemów operacyjnych, w których jądro na to pozwala, o ile system plików dostarcza dane. Różnica polega /devna tym, devfsże system plików został napisany, aby umożliwić to na początku, podczas gdy /system plików APFS pomija tę funkcję jako niepotrzebną we współczesnych czasach.

Oświadczenie: Właściwie nie przeprowadziłem żadnych badań dotyczących BSD ani macOS. Po prostu to latam.

grawitacja
źródło
To wydaje się mieć sens. Czy są jakieś inne sekcje pamięci, które różnią się od standardowego systemu plików OS? Założyłem, /etcże tak, więc wykorzystałem to jako mój punkt odniesienia.
haboutnnah
2
Przeciwnie, ogólnie / etc to tylko zwykły folder zawierający zwykłe pliki. Nie mogą być inne wirtualne systemy plików chociaż - uruchomić mountlub /sbin/mountzobaczyć, co się aktualnie zamontowany gdzie.
grawity
Masz rację! Zobacz: i.imgur.com/pcVpo1o.png
haboutnnah
To jest naprawdę fajne @grawity, i.imgur.com/8QuR0FK.png
haboutnnah
6
@houtouthh Twój zrzut ekranu potwierdza, że /devjest to wirtualny system plików korzystający ze devfssterownika, podczas gdy /etcjest on częścią /systemu plików używającego apfssterownika. Powodem, dla którego catczytać będzie jeden, a nie drugi, jest różnica między sterownikami apfsa devfs.
kasperd