¿Por qué puedo cat / dev?

41

Puedo cat /dev, puedo ls /dev, no puedo less /dev. ¿Por qué catme deja cateste directorio pero no otros directorios?

Imagen de este comportamiento en zsh.

haboutnnah
fuente
@KamilMaciorowski, aquí está el resultado y neofetchpara su información :) i.imgur.com/3azpnDt.png
haboutnnah

Respuestas:

43

Históricamente (hasta V7 UNIX, o alrededor de 1979) la readllamada al sistema funcionó tanto en archivos como en directorios. readen un directorio devolvería una estructura de datos simple que un programa de usuario analizaría para obtener las entradas del directorio. De hecho, la lsherramienta V7 hizo exactamente esto: readen un directorio, analiza la estructura de datos resultante, la salida en un formato de lista estructurada.

A medida que los sistemas de archivos se volvieron más complejos, esta estructura de datos "simple" se volvió más complicada, hasta el punto en que readdirse agregó una función de biblioteca para ayudar a los programas a analizar la salida de read(directory). Los diferentes sistemas y sistemas de archivos pueden tener diferentes formatos en disco, lo que se estaba volviendo complicado.

Cuando Sun presentó el Sistema de archivos de red (NFS), querían abstraer completamente la estructura de directorios en el disco. read(directory)Sin embargo, en lugar de hacer que su devolución sea una representación del directorio independiente de la plataforma, agregaron una nueva llamada al sistema getdirents- y prohibieron readlos directorios montados en la red. Esta llamada al sistema se adaptó rápidamente para trabajar en todos los directorios en varios tipos de UNIX, por lo que es la forma predeterminada de obtener el contenido de los directorios. (Historia resumida de https://utcc.utoronto.ca/~cks/space/blog/unix/ReaddirHistory )

Debido a readdirque ahora es la forma predeterminada de leer directorios, read(directory)generalmente no se implementa (devolviendo -EISDIR) en la mayoría de los sistemas operativos modernos (QNX, por ejemplo, es una notable excepción que se implementa readdircomo read(directory)). Sin embargo, con el diseño del "sistema de archivos virtual" en la mayoría de los núcleos modernos, en realidad depende del sistema de archivos individual si la lectura de un directorio funciona o no.

Y, de hecho, en macOS, el devfssistema de archivos subyacente al punto de /devmontaje realmente admite la lectura ( 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);

Esto llama explícitamente READDIRsi intenta leer /dev(la lectura de archivos bajo /devse maneja mediante una función separada - devfsspec_read). Entonces, si un programa llama a la readllamada del sistema /dev, ¡tendrá éxito y obtendrá una lista de directorio!

Esta es efectivamente una característica que es remanente desde los primeros días de UNIX, y que no se ha tocado en mucho tiempo. Una parte de mí sospecha que esto se mantiene por alguna razón de compatibilidad con versiones anteriores, pero podría ser el hecho de que a nadie le importa lo suficiente como para eliminar la función, ya que realmente no está dañando nada.

nneonneo
fuente
Probablemente este último, ya que se ha eliminado de la mayoría de los directorios.
user253751
36

Less es un visor de archivos de texto, cat es una herramienta para copiar datos arbitrarios. Por lo tanto, menos realiza su propia verificación para asegurarse de que no está abriendo algo que tendrá grandes cantidades de datos o se comportará de manera muy extraña. Por otro lado, cat no tiene tal verificación en absoluto: si el núcleo le permite abrir algo (incluso si es una tubería o un dispositivo o algo peor), cat lo leerá.

Entonces, ¿por qué el sistema operativo permite que cat abra directorios? Tradicionalmente, en los sistemas de estilo BSD, todos los directorios podían leerse como archivos, y así era como los programas enumerarían un directorio en primer lugar: simplemente interpretando las estructuras directas almacenadas en el disco.

Más tarde, esas estructuras en el disco comenzaron a divergir de la dirección utilizada por el núcleo: donde anteriormente un directorio era una lista lineal, los sistemas de archivos posteriores comenzaron a usar tablas hash, árboles B, etc. Así que leer directorios directamente ya no era sencillo: el núcleo creció funciones dedicadas para esto. (No estoy seguro de si esa fue la razón principal, o si se agregaron principalmente por otras razones, como el almacenamiento en caché).

Algunos sistemas BSD continúan permitiéndole abrir todos los directorios para leer; No sé si le dan los datos sin procesar del disco, o si en su lugar devuelven una lista directa emulada, o si dejan que el controlador del sistema de archivos decida.

Entonces, quizás macOS es uno de esos sistemas operativos donde el núcleo lo permite siempre que el sistema de archivos proporcione los datos. Y la diferencia es que /devestá en un devfssistema de archivos que fue escrito para permitir esto en los primeros días, mientras que /está en un sistema de archivos APFS que omitió esta característica como innecesaria en los tiempos modernos.

Descargo de responsabilidad: en realidad no he realizado ninguna investigación sobre BSD o macOS. Solo lo estoy volando.

Gravedad
fuente
Esto parece tener sentido. ¿Hay otras secciones de almacenamiento que difieren del sistema de archivos estándar del sistema operativo? Supuse que /etcsí, así que lo usé como mi punto de referencia.
Haboutnnah
2
Por el contrario, generalmente / etc es solo una carpeta normal que contiene archivos regulares. Sin embargo, puede haber otros sistemas de archivos virtuales: ejecutar mounto /sbin/mountver qué está montado actualmente en dónde.
Grawity
¡Tienes razón! Vea esto: i.imgur.com/pcVpo1o.png
haboutnnah
Esto es realmente genial @grawity, i.imgur.com/8QuR0FK.png
haboutnnah
66
@haboutnnah Su captura de pantalla confirma que /deves un sistema de archivos virtual que usa el devfscontrolador, mientras que /etces parte del /sistema de archivos que usa el apfscontrolador. Entonces, la razón catleerá uno y no el otro es una diferencia entre los controladores apfsy devfs.
Kasperd