¿Por qué es / dev / null un archivo? ¿Por qué no se implementa su función como un programa simple?


114

Estoy tratando de entender el concepto de archivos especiales en Linux. Sin embargo, tener un archivo especial en /devparece simplemente tonto cuando su función podría implementarse mediante un puñado de líneas en C, que yo sepa.

Además, podría usarlo de la misma manera, es decir, conectarlo en nulllugar de redirigirlo /dev/null. ¿Hay alguna razón específica para tenerlo como archivo? ¿Convertirlo en un archivo no causa muchos otros problemas, como demasiados programas que acceden al mismo archivo?


20
Por cierto, gran parte de esta sobrecarga es también por qué cat foo | bares mucho peor (a escala) que bar <foo. cates un programa trivial, pero incluso un programa trivial crea costos (algunos de ellos específicos de la semántica FIFO) porque los programas no pueden seek()dentro de FIFO, por ejemplo, un programa que podría implementarse eficientemente con la búsqueda puede terminar haciendo operaciones mucho más costosas cuando se le da una canalización; con un dispositivo de caracteres como /dev/nulleste puede falsificar esas operaciones, o con un archivo real puede implementarlas, pero un FIFO no permite ningún tipo de manejo contextualizado).
Charles Duffy

13
grep blablubb file.txt 2>/dev/null && dosomethingno podría funcionar con null siendo un programa o una función.
rexkogitans

16
Puede que le resulte esclarecedor (o al menos alucinante) leer sobre el sistema operativo Plan 9 para ver hacia dónde se dirigía la visión de "todo es un archivo". Se vuelve un poco más fácil ver el poder de tener recursos disponibles como archivo caminos una vez que vea un sistema que abraza completamente el concepto (en lugar de en su mayoría / parcialmente, como lo hace Linux / Unix moderno).
mtraceur

25
Además de que nadie señaló que un controlador de dispositivo que se ejecuta en el espacio del kernel es un programa con "un puñado de líneas de C" , ninguna de las respuestas hasta ahora ha abordado la suposición de "demasiados programas que acceden al mismo archivo" en la pregunta
JdeBP

12
Re "su función podría ser implementado por un puñado de líneas en C": Usted no lo creería, pero es implementado por un puñado de líneas en C! Por ejemplo, el cuerpo de la readfunción para /dev/nullconsiste en un "retorno 0" (lo que significa que no hace nada y, supongo, da como resultado un EOF): (Desde static github.com/torvalds/linux/blob/master/ drivers / char / mem.c ) ssize_t read_null(struct file *file, char __user *buf, size_t count, loff_t *ppos) { return 0; }(Oh, acabo de ver que @JdeBP ya hizo ese punto. De todos modos, aquí está la ilustración :-).
Peter A. Schneider

Respuestas:


153

Además de los beneficios de rendimiento del uso de un dispositivo con caracteres especiales, el beneficio principal es la modularidad . / dev / null puede usarse en casi cualquier contexto donde se espera un archivo, no solo en las tuberías de shell. Considere los programas que aceptan archivos como parámetros de línea de comandos.

# We don't care about log output.
$ frobify --log-file=/dev/null

# We are not interested in the compiled binary, just seeing if there are errors.
$ gcc foo.c -o /dev/null  || echo "foo.c does not compile!".

# Easy way to force an empty list of exceptions.
$ start_firewall --exception_list=/dev/null

Todos estos son casos en los que usar un programa como fuente o sumidero sería extremadamente engorroso. Incluso en el caso de la canalización de shell, stdout y stderr pueden redirigirse a archivos de forma independiente, algo que es difícil de hacer con ejecutables como sumideros:

# Suppress errors, but print output.
$ grep foo * 2>/dev/null

14
Además, no se usa /dev/nullsolo en los comandos del shell. Puede usarlo en otros parámetros suministrados a un software, por ejemplo, en archivos de configuración. --- Para el software esto es muy conveniente. No necesita hacer una diferencia entre /dev/nully un archivo normal.
pabouk

No estoy seguro de entender que la parte sobre redirecciones separadas para hundir ejecutables es difícil. En C, solo hace un pipe, forky execvecomo cualquier otra tubería de proceso, solo con cambios en las dup2llamadas que configuran las conexiones, ¿verdad? Es cierto que la mayoría de los shells no ofrecen las formas más bonitas de hacer eso, pero presumiblemente si no tuviéramos tanto patrón de dispositivo como archivo y la mayoría de las cosas /devy /procfueran tratados como ejecutables, los shells se habrían diseñado con formas para hacerlo tan fácilmente como redirigimos ahora.
aschepler

66
@aschepler Es que no redirigir a los ejecutables del receptor es difícil. Es que escribir aplicaciones que pueden escribir / leer desde ambos archivos y el sumidero nulo sería más complicado si el sumidero nulo no fuera un archivo. A menos que esté hablando de un mundo donde, en lugar de que todo sea un archivo, ¿todo es un ejecutable? Ese sería un modelo muy diferente al que tienes en * nix OS.
Cubic

1
@aschepler Te olvidaste wait4! Tiene razón, es ciertamente posible canalizar stdout y stderr a diferentes programas usando apis POSIX, y puede ser posible inventar una sintaxis de shell inteligente para redirigir stdout y stderr a diferentes comandos. Sin embargo, no estoy al tanto de ningún shell de este tipo en este momento, y el punto más importante es que / dev / null encaja perfectamente en las herramientas existentes (que en gran medida funcionan con archivos), y / bin / null no lo haría. También podríamos imaginar alguna API de E / S que facilite que gcc envíe (de forma segura) a un programa como a un archivo, pero esa no es la situación en la que estamos.
ioctl

2
@ioctl con respecto a las conchas; tanto zsh como bash al menos le permitirán hacer cosas como grep localhost /dev/ /etc/hosts 2> >(sed 's/^/STDERR:/' > errfile ) > >(sed 's/^/STDOUT:/' > outfile), el resultado se procesa por separado errfileyoutfile
Matija Nalis

62

Para ser justos, no es un archivo regular per se; Es un dispositivo especial de caracteres :

$ file /dev/null
/dev/null: character special (3/2)

Funciona como un dispositivo en lugar de como un archivo o programa, lo que significa que es una operación más simple para redirigir la entrada o la salida, ya que se puede adjuntar a cualquier descriptor de archivo, incluida la entrada / salida / error estándar.


24
cat file | nulltendría mucha sobrecarga, primero en configurar una tubería, engendrar un proceso, ejecutar "nulo" en el nuevo proceso, etc. Además, nullusaría bastante CPU en un bucle leyendo bytes en un búfer que luego simplemente descartado ... La implementación de /dev/nullen el núcleo es más eficiente de esa manera. Además, ¿qué pasa si desea pasar /dev/nullcomo argumento, en lugar de una redirección? (¡Podrías usar <(...)en bash, pero eso es mucho más pesado!)
filbranden

44
Si tuviera que canalizar a un programa llamado nullEn lugar de usar la redirección a /dev/null, ¿habría una manera simple y clara de decirle al shell que ejecute un programa mientras envía solo su stderr a nulo?
Mark Plotnick

55
Esta es una configuración realmente costosa para una demostración general. Sugeriría usar en su /dev/zerolugar.
chrylis -on strike-

20
Esos ejemplos están mal. dd of=-escribe en un archivo llamado -, simplemente omita el of=para escribir en stdout, ya que es donde ddescribe por defecto. La tubería falseno funcionaría, ya falseque no lee su stdin, por ddlo que sería asesinado con un SIGPIPE. Para un comando que descarta su entrada se puede utilizar ... cat > /dev/null. También la comparación que probablemente sea irrelevante como el cuello de la botella probablemente sería la generación de números aleatorios aquí.
Stéphane Chazelas

8
Las versiones AST de ddetc. ni siquiera se molestan en realizar una llamada al sistema de escritura cuando detectan que el destino es / dev / null.
Mark Plotnick

54

Sospecho que el por qué tiene mucho que ver con la visión / diseño que dio forma a Unix (y, en consecuencia, Linux), y las ventajas derivadas de ello.

Sin duda, hay un beneficio de rendimiento no despreciable al no acelerar un proceso adicional, pero creo que hay más: unix temprano tenía una metáfora de "todo es un archivo", que tiene una ventaja no obvia pero elegante si se mira desde una perspectiva del sistema, en lugar de una perspectiva de script de shell.

Digamos que tiene su nullprograma de línea de comandos y /dev/nullel nodo del dispositivo. Desde una perspectiva de script de shell, el foo | nullprograma es realmente útil y conveniente , y foo >/dev/nulltoma un poco más de tiempo para escribir y puede parecer extraño.

Pero aquí hay dos ejercicios:

  1. Vamos a implementar el programa nullusando las herramientas Unix existentes y /dev/null- fácil: cat >/dev/null. Hecho.

  2. ¿Se puede implementar /dev/nullen términos de null?

Tiene toda la razón en que el código C para descartar la entrada es trivial, por lo que puede que aún no sea obvio por qué es útil tener un archivo virtual disponible para la tarea.

Considere: casi todos los lenguajes de programación ya necesitan trabajar con archivos, descriptores de archivos y rutas de archivos, porque formaron parte del paradigma "todo es un archivo" de Unix desde el principio.

Si todo lo que tiene son programas que escriben en stdout, bueno, al programa no le importa si los redirige a un archivo virtual que traga todas las escrituras, o una tubería a un programa que traga todas las escrituras.

Ahora, si tiene programas que toman rutas de archivos para leer o escribir datos (lo que hace la mayoría de los programas), y desea agregar la funcionalidad de "entrada en blanco" o "descartar esta salida" a esos programas, bueno, /dev/nulleso es gratis.

Tenga en cuenta que la elegancia de esto es que reduce la complejidad del código de todos los programas involucrados: para cada caso de uso común pero especial que su sistema puede proporcionar como un "archivo" con un "nombre de archivo" real, su código puede evitar agregar un comando personalizado Opciones de línea y rutas de código personalizadas para manejar.

La buena ingeniería de software a menudo depende de encontrar metáforas buenas o "naturales" para abstraer algún elemento de un problema de una manera que sea ​​más fácil de pensar pero que sea flexible , para que pueda resolver básicamente el mismo rango de problemas de nivel superior sin tener que dedicar el tiempo y la energía mental a reimplementar soluciones a los mismos problemas de nivel inferior constantemente.

"Todo es un archivo" parece ser una de esas metáforas para acceder a los recursos: se llama opena una ruta determinada en un espacio de nombres jerárquico, se obtiene una referencia (descriptor de archivo) al objeto, y se puede ready write, etc., en los descriptores de archivo. Sus stdin / stdout / stderr también son descriptores de archivos que se abrieron previamente para usted. Sus tuberías son solo archivos y descriptores de archivos, y la redirección de archivos le permite pegar todas estas piezas juntas.

Unix tuvo tanto éxito como en parte debido a lo bien que funcionaron estas abstracciones juntas, y /dev/nullse entiende mejor como parte de ese todo.


PD Vale la pena mirar la versión Unix de "todo es un archivo" y cosas /dev/nullcomo los primeros pasos hacia una generalización más flexible y poderosa de la metáfora que se ha implementado en muchos sistemas que siguieron.

Por ejemplo, en Unix, los objetos especiales como archivos /dev/nulltuvieron que implementarse en el núcleo en sí, pero resulta que es lo suficientemente útil como para exponer la funcionalidad en forma de archivo / carpeta que desde entonces se han creado múltiples sistemas que proporcionan una forma para los programas Para hacer eso.

Uno de los primeros fue el sistema operativo Plan 9, creado por algunas de las mismas personas que crearon Unix. Más tarde, GNU Hurd hizo algo similar con sus "traductores". Mientras tanto, Linux terminó recibiendo FUSE (que ahora también se ha extendido a los otros sistemas convencionales).


8
@PeterCordes el punto de la respuesta comienza desde una posición de no entender el diseño. Si todos ya entendieran el diseño, esta pregunta no existiría.
OrangeDog

1
@mtraceur: ¿ Montar un archivo de imagen sin permiso de root? muestra alguna evidencia de que FUSE podría no requerir root, pero no estoy seguro.
Peter Cordes

1
@PeterCordes RE: "parece extraño": no es una disculpa por el diseño, solo un reconocimiento de cómo puede parecer si no está pensando en la implementación del sistema y aún no ha tenido el momento eureka sobre el sistema -todas las ventajas de diseño. Traté de aclarar eso abriendo esa oración con "desde una perspectiva de scripting de shell", y aludiendo al contraste entre eso y una perspectiva del sistema un par de oraciones antes. Pensándolo mejor, "puede parecer extraño" es mejor, así que lo modificaré. Agradezco más sugerencias de redacción para hacerlo más claro sin hacerlo demasiado detallado.
mtraceur

2
Lo primero que me dijeron cuando era un joven ingeniero en relación con Unix fue "Todo es un archivo" y juro que puedes escuchar las capitales. Y tomar esa idea temprano hace que Unix / Linux parezca mucho más fácil de entender. Linux heredó la mayor parte de esa filosofía de diseño. Me alegra que alguien lo haya mencionado.
StephenG

2
@PeterCordes, DOS "resolvió" el problema de escritura al hacer que el nombre de archivo mágico NULaparezca en cada directorio, es decir, todo lo que tiene que escribir es > NUL.
Cristian Ciupitu

15

Creo que /dev/nulles un dispositivo de caracteres (que se comporta como un archivo ordinario) en lugar de un programa por razones de rendimiento .

Si fuera un programa, sería necesario cargar, iniciar, programar, ejecutar y luego detener y descargar el programa. El programa simple de C que está describiendo, por supuesto, no consumiría muchos recursos, pero creo que hace una diferencia significativa al considerar un gran número (digamos millones) de acciones de redireccionamiento / canalización, ya que las operaciones de gestión de procesos son costosas a gran escala. implican cambios de contexto.

Otra suposición: la conexión a un programa requiere que la memoria sea asignada por el programa receptor (incluso si se descarta directamente después). Entonces, si conecta la herramienta, tiene el doble de consumo de memoria, una vez en el programa de envío y otra vez en el programa de recepción.


10
No es solo el costo de instalación, es que cada escritura en una tubería requiere copia de memoria y un cambio de contexto al programa de lectura. (O al menos un cambio de contexto cuando el buffer de la tubería está lleno. Y el lector tiene que hacer otra copia cuando se trata de readlos datos). ¡Esto no es insignificante en un PDP-11 de un solo núcleo donde se diseñó Unix! El ancho de banda de la memoria / copia es mucho más barato hoy de lo que era entonces. Una writellamada del sistema a un FD abierto /dev/nullpuede regresar de inmediato sin siquiera leer ningún dato del búfer.
Peter Cordes

@PeterCordes, mi nota es tangencial, pero es posible que, paradójicamente, las memorias escritas hoy sean más caras que nunca. Una CPU de 8 núcleos potencialmente realiza 16 operaciones enteras en un tiempo de reloj, mientras que una escritura de memoria de extremo a extremo se completaría en, por ejemplo, 16 relojes (CPU de 4 GHz, RAM de 250 MHz). Ese es el factor de 256. ¡La RAM para la CPU moderna es como un RL02 para la CPU PDP-11, casi como una unidad de almacenamiento periférica! :) No es tan sencillo, naturalmente, pero todo lo que llegue al caché se escribirá, y las escrituras inútiles privarían a otros cálculos del espacio de caché siempre importante.
kkm

@kkm: Sí, desperdiciando aproximadamente 2x 128kB de huella de caché L3 en un buffer de tubería en el kernel y un buffer de lectura en el nullprograma apestaría, pero la mayoría de las CPU multi-core no se ejecutan con todos los núcleos ocupados todo el tiempo, por lo que El tiempo de CPU para ejecutar el nullprograma es principalmente gratuito. En un sistema con todos los núcleos vinculados, la tubería inútil es un problema mayor. Pero no, un búfer "activo" se puede reescribir muchas veces sin descargarlo en la RAM, por lo que en su mayoría solo estamos compitiendo por el ancho de banda L3, no por el caché. No es genial, especialmente en un sistema SMT (hyperthreading) donde compiten otros núcleos lógicos en el mismo físico ...
Peter Cordes

.... Pero su cálculo de memoria es muy defectuoso. Las CPU modernas tienen mucho paralelismo de memoria, por lo que, aunque la latencia a DRAM es algo así como 200-400 ciclos de reloj de núcleo y L3> 40, el ancho de banda es de ~ 8 bytes / reloj. (Sorprendentemente, el ancho de banda de un solo hilo a L3 o DRAM es peor en un Xeon de muchos núcleos con memoria de cuatro canales frente a un escritorio de cuatro núcleos, porque está limitado por la concurrencia máxima de solicitudes que un núcleo puede mantener en vuelo. Ancho de banda = max_concurrency / latencia: ¿Por qué Skylake es mucho mejor que Broadwell-E para el rendimiento de memoria de un solo subproceso? )
Peter Cordes

... Ver también 7-cpu.com/cpu/Haswell.html para obtener los números de Haswell que comparan los núcleos cuádruples y los 18 núcleos. De todos modos, sí, las CPU modernas pueden hacer una cantidad ridícula de trabajo por reloj, si no están atascados esperando memoria. Sus números parecen ser solo 2 operaciones de ALU por reloj, como quizás un Pentium de 1993, o un ARM moderno de baja emisión de doble emisión. Un Ryzen o Haswell potencialmente realiza 4 operaciones ALU de enteros escalares + 2 operaciones de memoria por núcleo por reloj, o mucho más con SIMD. por ejemplo, Skylake-AVX512 tiene (por núcleo) un rendimiento de 2 por reloj en vpaddd zmm: 16 elementos de 32 bits por instrucción.
Peter Cordes

7

Además de "todo es un archivo" y, por lo tanto, la facilidad de uso en todos los lugares en los que se basan la mayoría de las otras respuestas, también hay un problema de rendimiento como menciona @ user5626466.

Para mostrar en la práctica, crearemos un programa simple llamado nullread.c:

#include <unistd.h>
char buf[1024*1024];
int main() {
        while (read(0, buf, sizeof(buf)) > 0);
}

y compilarlo con gcc -O2 -Wall -W nullread.c -o nullread

(Nota: no podemos usar lseek (2) en las tuberías, por lo que la única forma de drenar la tubería es leerla hasta que esté vacía).

% time dd if=/dev/zero bs=1M count=5000 |  ./nullread
5242880000 bytes (5,2 GB, 4,9 GiB) copied, 9,33127 s, 562 MB/s
dd if=/dev/zero bs=1M count=5000  0,06s user 5,66s system 61% cpu 9,340 total
./nullread  0,02s user 3,90s system 41% cpu 9,337 total

mientras que con la /dev/nullredirección de archivos estándar obtenemos velocidades mucho mejores (debido a los hechos mencionados: menos cambio de contexto, el núcleo simplemente ignora los datos en lugar de copiarlos, etc.):

% time dd if=/dev/zero bs=1M count=5000 > /dev/null
5242880000 bytes (5,2 GB, 4,9 GiB) copied, 1,08947 s, 4,8 GB/s
dd if=/dev/zero bs=1M count=5000 > /dev/null  0,01s user 1,08s system 99% cpu 1,094 total

(Esto debería ser un comentario allí, pero es demasiado grande para eso y sería completamente ilegible)


¿En qué hardware probaste? 4.8GB / s es bastante bajo en comparación con los 23GB / s que obtengo en un Skylake i7-6700k (DDR4-2666, pero el búfer debería mantenerse caliente en la caché L3. Por lo tanto, una buena parte del costo es que las llamadas al sistema son caras con Spectre + Mitigación de fusión habilitada. Eso duele doblemente para las tuberías, porque los amortiguadores de tubería son más pequeños que 1M, por lo que son más llamadas al sistema de escritura / lectura. Sin embargo, casi 10 veces la diferencia de rendimiento es peor de lo que esperaba. Sin embargo, en mi sistema Skylake es 23GB / s vs. 3.3GB / s , ejecutando x86-64 Linux 4.15.8-1-ARCH, entonces eso es un factor de 6.8. Wow, las llamadas al sistema son caras ahora)
Peter Cordes

1
@PeterCordes 3GB / s con 64k topes de tubería sugiere 2x 103124 syscalls por segundo ... y esa cantidad de cambios de contexto, je. En una CPU del servidor, con 200000 llamadas al sistema por segundo, puede esperar una sobrecarga del 8% de PTI, ya que hay muy poco conjunto de trabajo. (El gráfico al que me refiero no incluye la optimización PCID, pero tal vez eso no sea tan significativo para pequeños conjuntos de trabajo). ¿Entonces no estoy seguro de que PTI tenga un gran impacto allí? brendangregg.com/blog/2018-02-09/…
sourcejedi

1
Oh interesante, entonces es un Silvermont con 2MB de caché L2 , por lo que su ddbuffer + buffer de recepción no cabe; probablemente esté tratando con el ancho de banda de memoria en lugar del ancho de banda de caché de último nivel. Puede obtener un mejor ancho de banda con 512k buffers o incluso 64k buffers. (De acuerdo con stracemi escritorio, writey readestoy devolviendo 1048576, por lo que creo que eso significa que solo estamos pagando al usuario <-> costo del núcleo de invalidación TLB + descarga de predicción de sucursal una vez por MiB, no por 64k, @sourcejedi. Es Specter mitigación que tiene el mayor costo, creo)
Peter Cordes

1
@sourcejedi: Con la mitigación de Spectre habilitada, el costo de una syscalldevolución inmediata ENOSYSes de ~ 1800 ciclos en Skylake con la mitigación de Spectre habilitada, siendo la mayor parte la wrmsrque invalida la BPU, según las pruebas de @ BeeOnRope . Con la mitigación desactivada, el tiempo de ida y vuelta usuario-> kernel-> usuario es ~ 160 ciclos. Pero si está tocando mucha memoria, la mitigación de Meltdown también es significativa. Hugepages debería ayudar (se deben recargar menos entradas TLB).
Peter Cordes

1
@PeterCordes En un sistema unix de un solo núcleo, seguramente veríamos 1 cambio de contexto por 64K, o lo que sea que fuera su búfer de tubería, y eso dolería ... en realidad también veo el [mismo número de cambios de contexto con 2 núcleos de CPU] ( unix.stackexchange.com/questions/439260/… ); también debe contar un ciclo de sueño / vigilia por cada 64k como cambio de contexto (a un "proceso inactivo" nominal). Mantener los procesos de canalización en la misma CPU realmente funcionó más del doble de rápido.
sourcejedi

6

Su pregunta se plantea como si algo se ganara quizás con simplicidad utilizando un programa nulo en lugar de un archivo. Quizás podamos deshacernos de la noción de "archivos mágicos" y, en su lugar, tener simplemente "tuberías normales".

Pero considere, una tubería también es un archivo . Normalmente no tienen nombre, por lo que solo pueden manipularse a través de sus descriptores de archivo.

Considere este ejemplo un tanto artificial:

$ echo -e 'foo\nbar\nbaz' | grep foo
foo

Usando la sustitución del proceso de Bash podemos lograr lo mismo a través de una forma más indirecta:

$ grep foo <(echo -e 'foo\nbar\nbaz')
foo

Reemplace el grepparaecho y podemos ver debajo de las cubiertas:

$ echo foo <(echo -e 'foo\nbar\nbaz')
foo /dev/fd/63

los <(...) construcción simplemente se reemplaza con un nombre de archivo, y grep cree que está abriendo cualquier archivo antiguo, simplemente se llama así /dev/fd/63. Aquí, /dev/fdhay un directorio mágico que crea canalizaciones con nombre para cada descriptor de archivo que posee el archivo que accede a él.

Podríamos hacer que sea menos mágico mkfifohacer una tubería con nombre que aparezca en lstodo, como un archivo ordinario:

$ mkfifo foofifo
$ ls -l foofifo 
prw-rw-r-- 1 indigo indigo 0 Apr 19 22:01 foofifo
$ grep foo foofifo

En otra parte:

$ echo -e 'foo\nbar\nbaz' > foofifo

y he aquí, saldrá grep foo.

Creo que una vez que te das cuenta de que las tuberías y los archivos normales y los archivos especiales como / dev / null son solo archivos, es evidente que implementar un programa nulo es más complejo. El núcleo tiene que manejar las escrituras en un archivo de cualquier manera, pero en el caso de / dev / null, simplemente puede dejar las escrituras en el piso, mientras que con una tubería tiene que transferir los bytes a otro programa, que luego tiene que en realidad leerlos.


@Lyle ¿Sí? Entonces, ¿por qué se imprime echo /dev/fd/63?
Phil Frost

Hm. Buen punto. Bueno, esto es implementado por shells, así que quizás tu shell sea diferente del viejo shell Bourne con el que crecí.
Lyle

Una diferencia es que echo no se lee desde stdin, mientras que grep sí, pero no puedo pensar cómo el shell lo sabría antes de ejecutarlos.
Lyle

1
Y strace aclara esto: para mí. lo tienes exactamente bien, con bash. La construcción '<(...)' está haciendo algo bastante diferente de <nombre de archivo. Hm. Aprendí algo
Lyle

0

Yo diría que hay un problema de seguridad más allá de los paradigmas históricos y el rendimiento. Limitar la cantidad de programas con credenciales de ejecución privilegiadas, por simple que sea, es un principio fundamental de la seguridad del sistema. /dev/nullCiertamente, se requeriría un reemplazo para tener tales privilegios debido al uso por parte de los servicios del sistema. Los marcos de seguridad modernos hacen un excelente trabajo al prevenir exploits, pero no son infalibles. Un dispositivo controlado por el núcleo al que se accede como un archivo es mucho más difícil de explotar.


Esto suena como una tontería. Escribir un controlador de kernel sin errores no es más fácil que escribir un programa sin errores que lea + descarte su stdin. No tiene por qué ser setuid o nada, por lo tanto /dev/null, o un programa de entrada-descartando propuesto, el vector de ataque sería el mismo: conseguir un script o programa que se ejecuta como root para hacer algo raro (como tratar de lseeken /dev/nullo abiertos varias veces desde el mismo proceso, o IDK, o invocar /bin/nullcon un entorno extraño, o lo que sea).
Peter Cordes

0

Como otros ya señalaron, /dev/null es un programa hecho de un puñado de líneas de código. Es solo que estas líneas de código son parte del núcleo.

Para aclararlo, aquí está la implementación de Linux: un dispositivo de caracteres llama a funciones cuando se lee o se escribe en ellas. Escribir en /dev/nullllamadas write_null , mientras lee llamadas read_null , registradas aquí .

Literalmente un puñado de líneas de código: estas funciones no hacen nada. Necesitaría más líneas de código que dedos en sus manos solo si cuenta funciones distintas a leer y escribir.


Tal vez debería haberlo expresado con más precisión. Me refería a por qué implementarlo como un dispositivo char en lugar de un programa. Sería unas pocas líneas de cualquier manera, pero la implementación del programa sería decididamente más simple. Como las otras respuestas han señalado, hay bastantes beneficios en esto; jefe de eficiencia y portabilidad entre ellos.
Ankur S

Seguro. Acabo de agregar esta respuesta porque ver la implementación real fue divertido (lo descubrí hace poco), pero la verdadera razón es lo que otros señalaron.
Matthieu Moy

¡Yo también! Recientemente comencé a aprender dispositivos en Linux y las respuestas fueron bastante informativas
Ankur S

-2

Espero que también conozcas el / dev / chargen / dev / zero y otros como ellos, incluido / dev / null.

LINUX / UNIX tiene algunos de estos, disponibles para que las personas puedan hacer un buen uso de los MARCOS DE CÓDIGO BIEN ESCRITO.

Chargen está diseñado para generar un patrón de caracteres específico y repetitivo: es bastante rápido y superaría los límites de los dispositivos en serie y ayudaría a depurar los protocolos en serie que se escribieron y fallaron alguna prueba u otra.

Zero está diseñado para llenar un archivo existente o generar una gran cantidad de ceros

/ dev / null es solo otra herramienta con la misma idea en mente.

Todas estas herramientas en su kit de herramientas significan que tiene media oportunidad de hacer que un programa existente haga algo único sin tener en cuenta su (su necesidad específica) como dispositivos o reemplazos de archivos

Establezcamos un concurso para ver quién puede producir el resultado más emocionante dados solo los pocos dispositivos de personajes en su versión de LINUX.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.