¿Cómo se crean los archivos Linux "/ dev"?

112

Hay archivos especiales en Linux que no son realmente archivos.

Los ejemplos más notables y claros de estos están en la devcarpeta, "archivos" como:

  • /dev/null - Ignora todo lo que escribes en el archivo
  • /dev/random - Emite datos aleatorios en lugar del contenido de un archivo
  • /dev/tcp - Envía cualquier información que escriba a este archivo a través de la red

En primer lugar, ¿cuál es el nombre de este tipo de "archivos" que realmente son algún tipo de script o binario disfrazado?

Segundo, ¿cómo se crean? ¿Están estos archivos integrados en el sistema a nivel del núcleo, o hay una manera de crear un "archivo mágico" usted mismo (qué tal a /dev/rickroll)?

IQAndreas
fuente
1
No tenía idea de cómo etiquetar esta pregunta, especialmente porque no sé el nombre de lo que estoy buscando. Siéntase libre de editar en cualquier etiqueta relevante.
IQAndreas
15
Por cierto, esta es una parte fundamental del diseño de sistemas operativos Unix y similares a Unix: (casi) todo es un archivo, o se puede hacer que se vea como un archivo.
cas
55
Ver también: mknod (2) man 2 mknod
RobertL
44
Estos son "nodos de dispositivo". Sin embargo, los que mencionó, a diferencia de los asociados con discos, teclado, mouse, tarjetas de audio y otros dispositivos, son los llamados "pseudodispositivos", ya que no son dispositivos "reales" y solo existen en el núcleo. Es posible crear nuevos, escribiendo un controlador de dispositivo adecuado y agregarlo al núcleo (por ejemplo, un pseudodispositivo para monitorear alguna actividad en la computadora). Antes de que el directorio / dev existiera en el disco, actualmente es un sistema de archivos virtual (del tipo devfs) creado por el núcleo.
Baard Kopperud
10
Todos los archivos, incluso los archivos "reales", son artefactos de software. El software detrás de cada dispositivo, archivo, socket, archivo especial, o algo aún no se ha inventado proporciona una tabla de funciones para manejar open(), read(), close(), etc. Después de eso, le toca al software
waltinator

Respuestas:

101

/dev/zeroes un ejemplo de un "archivo especial", en particular, un "nodo de dispositivo". Normalmente, estos se crean por el proceso de instalación de distribución, pero se puede totalmente las crea usted mismo si quieres.

Si preguntas lssobre /dev/zero:

# ls -l /dev/zero
crw-rw-rw- 1 root root 1, 5  Nov 5 09:34 /dev/zero

La "c" al principio le dice que este es un "dispositivo de caracteres"; el otro tipo es "dispositivo de bloque" (impreso lscomo "b"). En términos generales, los dispositivos de acceso aleatorio como los discos duros tienden a ser dispositivos de bloque, mientras que las cosas secuenciales como las unidades de cinta o la tarjeta de sonido tienden a ser dispositivos de caracteres.

La parte "1, 5" es el "número de dispositivo principal" y el "número de dispositivo secundario".

Con esta información, podemos usar el mknodcomando para crear nuestro propio nodo de dispositivo:

# mknod foobar c 1 5

Esto crea un nuevo archivo llamado foobar, en la carpeta actual, que hace exactamente lo mismo que /dev/zero. (Por supuesto, puede establecer diferentes permisos si lo desea). Todo este "archivo" realmente contiene los tres elementos anteriores: tipo de dispositivo, número mayor, número menor. Puede usar lspara buscar los códigos de otros dispositivos y recrearlos también. Cuando te aburras, solo usa rmpara eliminar los nodos del dispositivo que acabas de crear.

Básicamente, el número principal le dice al kernel de Linux con qué controlador de dispositivo debe hablar, y el número menor le dice al controlador de dispositivo de qué dispositivo está hablando. (Por ejemplo, probablemente tenga un controlador SATA, pero tal vez haya varios discos duros conectados).

Si desea inventar nuevos dispositivos que hagan algo nuevo ... bueno, deberá editar el código fuente del kernel de Linux y compilar su propio kernel personalizado. ¡Entonces no hagamos eso! :-) Pero puedes agregar archivos de dispositivo que duplican los que ya tienes. Un sistema automatizado como udev básicamente solo está buscando eventos del dispositivo y llamando mknod/ rmpor usted automáticamente. Nada más mágico que eso.

Todavía hay otros tipos de archivos especiales:

  • Linux considera que un directorio es un tipo especial de archivo. (Por lo general, no puede abrir directamente un directorio, pero si pudiera, encontraría que es un archivo normal que contiene datos en un formato especial y le dice al núcleo dónde encontrar todos los archivos en ese directorio).

  • Un enlace simbólico es un archivo especial. (Pero un enlace rígido no lo es). Puede crear enlaces simbólicos con el ln -scomando. (Busque la página del manual).

  • También hay una cosa llamada "canalización con nombre" o "FIFO" (cola de primero en entrar, primero en salir). Puedes crear uno con mkfifo. Un FIFO es un archivo mágico que puede abrirse con dos programas a la vez: una lectura y una escritura. Cuando esto sucede, funciona como un tubo de cubierta normal. Pero puede iniciar cada programa por separado ...

Un archivo que no es "especial" de ninguna manera se denomina "archivo normal". De vez en cuando verá mención de esto en la documentación de Unix. Eso es lo que significa; un archivo que no es un nodo de dispositivo o un enlace simbólico o lo que sea. Solo un archivo normal, todos los días, sin propiedades mágicas.

Orquídea matemática
fuente
44
También hay un tipo más de archivo especial, un socket de dominio Unix vinculado al sistema de archivos.
Brian Bi
8
Si quieres jugar mknod, corre cat /proc/devicespara ver los números principales de todos los pilotos. Lo que nos lleva a otro tipo de archivo especial, el /procsistema de archivos ( esta respuesta habla de ello).
Ugoren
8
Otros Unices han inventado sus propios archivos especiales, por ejemplo, Solaris tenía puertas .
Kevin
66
Minipick: no tienes que volver a compilar el kernel para escribir un nuevo personaje / dispositivo de bloqueo :) crashcourse.ca/introduction-linux-kernel-programming/... ¡ De lo contrario, esta es una muy buena respuesta, +1!
Comandante Coriander Salamander
1
@MathematicalOrchid: un paso que falta en su respuesta (o al menos solo lo indica implícitamente) es el hecho de que esos archivos especiales no son scripts o binarios disfrazados (como la pregunta implica), sino más bien una interfaz para acceder a la funcionalidad que está presente en el kernel del sistema operativo.
Soñador
34

La mayoría de las /deventradas son inodos de dispositivo de bloque o inodos de dispositivo de caracteres. Wikipedia tiene muchos detalles sobre eso, que no voy a repetir.

Pero lo /dev/tcpque se menciona en su pregunta no se explica por ninguna de las respuestas existentes. /dev/tcpy /dev/udpson diferentes de la mayoría de las otras /deventradas. Los dispositivos de bloque y de carácter son implementadas por el kernel, pero /dev/tcpy /dev/udpse implementan en el modo de usuario.

El shell bash es un programa que tiene una implementación de /dev/tcpy /dev/udp(copiado de ksh93). Cuando intentas abrir una ruta debajo de las que tienen operadores de redireccionamiento bash, no realizará una openllamada normal al sistema. En cambio, bash creará un socket TCP y lo conectará al puerto especificado.

Esto se implementa en modo de usuario y solo en algunos programas, como se puede ver en el siguiente ejemplo, que demuestra la diferencia entre dejar bashe catintentar abrir/dev/tcp/::1/22

$ cat /dev/tcp/::1/22
cat: /dev/tcp/::1/22: No such file or directory
$ cat < /dev/tcp/::1/22
SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-2ubuntu2.3

Una diferencia con esto ksh93es que bashsolo hará esas conexiones TCP con operadores de redireccionamiento, no en los otros lugares donde puede abrir archivos como el sourceo .incorporado.

kasperd
fuente
Además, GNU awk gawkcasos especiales similares /inet{,4,6}/{tcp,udp}/$port/$remote/$rport, desde algún lugar alrededor de 2010 (no recuerdo exactamente y no puedo encontrar notas de la versión).
dave_thompson_085
66
En mi opinión, una mejor manera de expresar el punto /dev/tcpes que NO es un archivo. Nunca hay un archivo llamado esto. La sintaxis de Bash para abrir sockets usa la cadena /dev/tcp/addresscomo un nombre de archivo, pero llamarlo "archivo implementado en el espacio del usuario" suena extraño. Sin kshembargo, es interesante que enganche esos nombres de archivo para todo, no solo para los redireccionamientos. Eso está más cerca de "implementar un archivo".
Peter Cordes
@ PeterCordes, creo que UWIN los configura como archivos reales. y creo que 3dfs hace lo mismo. recuerde, bashsolo copió este comportamiento, pero se origina en otro lugar.
mikeserv
19

Además de los nodos de dispositivos explicados en otras respuestas (creadas con mknod (2) o suministradas por algunos devfs ), Linux tiene otros archivos "mágicos" proporcionados por sistemas de archivos virtuales especiales , en particular en /proc/(ver proc (5) , leer sobre procfs ) y en /sys/(leer sobre sysfs ).

Estos pseudo archivos (que aparecen -eg a stat (2) - como archivos normales, no como dispositivos) son una vista virtual proporcionada por el núcleo; en particular, leer desde /proc/(p. ej. cat /proc/$$/maps, con open (2) -ing /proc/self/statusen su programa) generalmente no implica ninguna E / S física desde el disco o la red, por lo que es bastante rápido.

Para crear un pseudo-archivo adicional /proc/, generalmente debe escribir su propio módulo de kernel y cargarlo (ver, por ejemplo, esto ).

Basile Starynkevitch
fuente
3
AFAIK la información sobre extender / proc está desactualizada. Aunque todavía es técnicamente posible, / proc (o más bien procfs) solo debe contener información sobre los procesos en ejecución. Todos los demás pseudoarchivos, incluidos los que contienen información de tiempo de ejecución u opciones de configuración para el núcleo, deben ir a / sys (sysfs). Todavía hay algunos pseudo archivos no relacionados con el proceso en / proc (por ejemplo, meminfo, cpuinfo) por razones de compatibilidad, pero los nuevos pseudo archivos deberían ir a sysfs.
Dreamer
13

Se llaman nodos de dispositivo y se crean de forma manual mknodo automática con udev. Por lo general, son interfaces en forma de archivos para dispositivos de caracteres o bloques con controladores en el núcleo; por ejemplo, los discos son dispositivos de bloque, ttys y puertos seriales, etc., son dispositivos de caracteres.

También hay otros tipos de archivos "especiales", que incluyen canalizaciones con nombre y fifos y sockets.

cas
fuente
9

Como otros usuarios ya han explicado con gran detalle, los archivos especiales requieren código para realizar una copia de seguridad. Sin embargo, nadie parece haber mencionado que Linux proporciona varias formas de escribir ese código en el espacio de usuario:

A. FUSE (Sistema de archivos en USErspace) le permite escribir algo como /procsin riesgo de bloquear el núcleo y hacerlo en el idioma / tiempo de ejecución de su elección, como Go , Node.js , Perl , PHP , Python , Ruby , Rust , etc .

También tiene la ventaja de que los sistemas de archivos FUSE se pueden montar sin sudoellos porque se ejecutan como el usuario que realiza el montaje.

Aquí hay algunos ejemplos de cosas que la gente ha escrito usando FUSE:

  • mp3fs (Vea sus archivos FLAC como archivos MP3 que se crean sobre la marcha cuando los copia / hace clic y los arrastra a su reproductor de MP3)
  • PyTagsFS (Vea sus medios en un árbol de carpetas virtuales creadas a partir de las etiquetas de metadatos)
  • fuse-zip (montar archivos Zip como carpetas)
  • FuseISO (Montar ISO sin permisos de root)
  • iFUSE (Mount iDevices)
  • FuseDAV ( montar acciones de WebDAV)
  • fuse-exfat ( montar sistemas de archivos con formato exFAT)
  • ntfs-3g ( el controlador NTFS de Linux)

B. Si desea crear un dispositivo de entrada virtual como un teclado, mouse, joystick, etc. (por ejemplo, para escribir un controlador de espacio de usuario para un dispositivo USB con el que está hablando libusb), hay una entrada .

Los enlaces son más difíciles de encontrar, pero sé que existen para Go (solo con teclado), Python y Ruby (2) .

Los ejemplos de uso de entrada real en el mundo real incluyen:

  • G15Daemon (controlador de Linux para la pantalla LCD y las teclas de juegos en los teclados de juegos Logitech G15)
  • ds4drv (controlador para controladores Sony DualShock 4)
  • xboxdrv (controlador de controlador XBox 360 alternativo y Linux equivalente a x360ce juegos tan mal diseñados como Runner2: Future Legend of Rhythm Alien pueden pensar que están hablando con un controlador XBox real cuando no lo están)
  • Los controladores antiguos de Wiimote, como cwiid, que se requerían antes de que alguien finalmente escribiera un controlador de núcleo de Wiimote para que el soporte estuviera disponible de forma predeterminada.

C. Para dispositivos de caracteres genéricos, hay CUSE (dispositivos de caracteres en USErspace). Sin embargo, es mucho menos popular.

El único usuario de la API CUSE que estoy personalmente en cuenta es el mismo programa que impulsó su creación: osspd , que implementa /dev/dsp, /dev/adspy /dev/mixer(la API de audio OSS) en el espacio de usuario para que puedan ser enrutados a través de PulseAudio o dmix.

El único enlace de CUSE que pude encontrar es cusepy , que no se ha actualizado desde 2010.

D. Es posible que no necesite un nuevo archivo especial en absoluto.

Por ejemplo, puede abrir la comunicación en bruto con cualquier dispositivo USB usando libusb (Lista de enlaces en la página) y luego comunicarse con otros programas a través de algún otro mecanismo (sockets TCP / UDP, lectura / escritura de stdin / stdout o archivos regulares en el disco , etc.)

ssokolow
fuente
1
Es posible que cusepy no se haya actualizado en un tiempo (de hecho, nunca se ha actualizado; ¡solo tiene un commit!), pero después de haber escrito un dispositivo de caracteres usando cusepy hace unas semanas, puedo confirmar que todavía funciona bien. Le faltaban algunas funciones relacionadas con la implementación poll, pero dado que cusepy usa ctypes y los enlaces se generan automáticamente en función de los archivos de encabezado C, corregir las funciones que faltan es solo cuestión de agregar el nombre de la función deseada a la lista de funciones exportadas en el setup.py.
Aleksi Torhamo
1
Otro ejemplo interesante del uso de FUSE es sshfs . Le permite navegar por el sistema de archivos remoto como si fuera local utilizando una conexión SSH debajo.
Mr. Deathless
@ Mr.Deathless Sí. En realidad lo uso y tenía la intención de mencionarlo, pero lo olvidé.
ssokolow
6

El libro Linux Device Drivers (altamente recomendado) explica esto en detalle, e incluso le hace crear un módulo de kernel que lo hace como un ejemplo, pero en pocas palabras, cada controlador de dispositivo tiene funciones específicas que se llaman cuando se abre, cierra un archivo , leer, escribir, etc. Los archivos "especiales" simplemente hacen algo especial dentro de esas funciones, en lugar de acceder al hardware de almacenamiento en un disco.

Por ejemplo, la función de escritura /dev/nullsimplemente no hace nada, ignorando los bytes. La función de lectura para /dev/randomdevuelve un número aleatorio.

Karl Bielefeldt
fuente
1

mount -t devtmpfs

También es interesante ver que en los sistemas modernos, /devnormalmente es un tipo de sistema de archivos que se puede montar donde lo desee. Ubuntu 16.04:

mkdir d
sudo mount -t devtmpfs none d
head -c 10 d/random
sudo umount d

Esto está habilitado por CONFIG_DEVTMPFS=yy permite que el núcleo mismo cree y destruya los archivos del dispositivo según sea necesario.

CONFIG_DEVTMPFS_MOUNT=y

Esta opción hace que el núcleo monte automáticamente devtmpfs /dev.

drivers/base/Kconfig documentos:

config DEVTMPFS_MOUNT
    bool "Automount devtmpfs at /dev, after the kernel mounted the rootfs"
    depends on DEVTMPFS
    help
      This will instruct the kernel to automatically mount the
      devtmpfs filesystem at /dev, directly after the kernel has
      mounted the root filesystem. The behavior can be overridden
      with the commandline parameter: devtmpfs.mount=0|1.
      This option does not affect initramfs based booting, here
      the devtmpfs filesystem always needs to be mounted manually
      after the rootfs is mounted.
      With this option enabled, it allows to bring up a system in
      rescue mode with init=/bin/sh, even when the /dev directory
      on the rootfs is completely empty.

file_operations

Finalmente, debe crear su propio módulo de kernel de dispositivo de caracteres para ver exactamente lo que está sucediendo.

Aquí hay un ejemplo ejecutable mínimo: Comprensión de los archivos de dispositivos de caracteres (o caracteres especiales)

El paso más importante es configurar la file_operationsestructura, por ejemplo:

static const struct file_operations fops = {
    .owner = THIS_MODULE,
    .read = read,
    .open = open,
};

static int myinit(void)
{
    major = register_chrdev(0, NAME, &fops);
    return 0;
}

que contiene punteros de función que se llaman para cada llamada al sistema relacionada con el archivo.

Entonces resulta obvio que anula esas llamadas al sistema relacionadas con archivos para hacer lo que quiera, y así es como el núcleo implementa los dispositivos /dev/zero.

Crear /deventradas automáticamente sinmknod

El misterio final es cómo el núcleo crea /deventradas automáticamente .

El mecanismo se puede observar haciendo un módulo de kernel que lo haga usted mismo como se muestra en: https://stackoverflow.com/questions/5970595/how-to-create-a-device-node-from-the-init-module- code-of-a-linux-kernel-module / 45531867 # 45531867 y se reduce a una device_createllamada.

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
fuente
En OpenBSD hay un script MAKEDEV que simplifica esto un poco, vea man.openbsd.org/MAKEDEV.8 No estoy seguro de por qué Linux no lo tiene, excepto que es mucho más complicado. Quizás las partes podrían ser adaptadas. Puede decir MKNOD tty, por ejemplo, y maneja los detalles.
Alan Corey