GNU/Linux >> Tutoriales Linux >  >> Linux

¿Cómo realiza Unix un seguimiento del directorio de trabajo de un usuario al navegar por el sistema de archivos?

Digamos que inicio sesión en un shell en un sistema Unix y empiezo a tocar los comandos. Inicialmente empiezo en el directorio de inicio de mi usuario ~ . Podría desde allí cd hasta el directorio Documents .

El comando para cambiar el directorio de trabajo aquí es muy simple e intuitivo de entender:el nodo principal tiene una lista de nodos secundarios a los que puede acceder, y presumiblemente utiliza una variante (optimizada) de una búsqueda para ubicar la existencia de un nodo secundario con el el nombre del usuario ingresado, y el directorio de trabajo se "modifica" para que coincida con esto; corríjame si me equivoco allí. Incluso puede ser más simple que el shell simplemente "ingenuamente" intente acceder al directorio exactamente según los deseos del usuario y cuando el sistema de archivos devuelva algún tipo de error, el shell muestre una respuesta en consecuencia.

Sin embargo, lo que me interesa es cómo funciona el mismo proceso cuando navego hacia arriba en un directorio, es decir, a un padre o al padre de un padre.

Dada mi ubicación desconocida, presumiblemente "ciega" de Documents , uno de posiblemente muchos directorios en todo el árbol del sistema de archivos con ese nombre, ¿cómo determina Unix dónde debo colocarme a continuación? ¿Hace referencia a pwd? y examinar eso? En caso afirmativo, ¿cómo pwd rastrear el estado de navegación actual?

Respuesta aceptada:

Las otras respuestas son simplificaciones excesivas, cada una presenta solo partes de la historia y están equivocadas en un par de puntos.

Hay dos formas en que se rastrea el directorio de trabajo:

  • Para cada proceso, en la estructura de datos del espacio del kernel que representa ese proceso, el kernel almacena dos referencias de vnode a los vnodes del directorio de trabajo y al directorio raíz de ese proceso. La referencia anterior la establece chdir() y fchdir() llamadas al sistema, la última por chroot() . Uno puede verlos indirectamente en /proc en sistemas operativos Linux o a través de fstat comando en FreeBSD y similares:

    % fstat -p $$|head -n 5
    USER     CMD          PID   FD MOUNT      INUM MODE         SZ|DV R/W
    JdeBP    zsh        92648 text /         24958 -r-xr-xr-x  702360  r
    JdeBP    zsh        92648 ctty /dev        148 crw--w----   pts/4 rw
    JdeBP    zsh        92648   wd /usr/home/JdeBP      4 drwxr-xr-x     124  r
    JdeBP    zsh        92648 root /             4 drwxr-xr-x      35  r
    % 

    Cuando opera la resolución de nombres de ruta, comienza en uno u otro de esos vnodes referenciados, según si la ruta es relativa o absoluta. (Hay una familia de …at() llamadas al sistema que permiten que la resolución del nombre de ruta comience en el vnode al que hace referencia un descriptor de archivo abierto (directorio) como tercera opción).

    En microkernel Unices, la estructura de datos está en el espacio de la aplicación, pero el principio de mantener referencias abiertas a estos directorios sigue siendo el mismo.

  • Internamente, dentro de shells como Z, Korn, Bourne Again, C y Almquist, el shell además realiza un seguimiento del directorio de trabajo mediante la manipulación de cadenas de una variable de cadena interna. Hace esto cada vez que tiene motivos para llamar a chdir() .

    Si uno cambia a un nombre de ruta relativo, manipula la cadena para agregar ese nombre. Si uno cambia a un nombre de ruta absoluto, reemplaza la cadena con el nuevo nombre. En ambos casos, ajusta la cadena para eliminar . y .. componentes y perseguir enlaces simbólicos reemplazándolos con sus nombres vinculados. (Aquí está el código del shell Z para eso, por ejemplo).

    El nombre en la variable de cadena interna es rastreado por una variable de shell llamado PWD (o cwd en las capas C). Esto se exporta convencionalmente como una variable de entorno (llamada PWD ) a los programas generados por el shell.

Estos dos métodos de rastrear cosas son revelados por -P y -L opciones al cd y pwd comandos integrados de shell, y por las diferencias entre los pwd integrados de los shells comandos y tanto el /bin/pwd comando y el pwd incorporado comandos de cosas como (entre otras) VIM y NeoVIM.

% mkdir a ; ln -s a b
% (cd b; pwd; /bin/pwd; printenv PWD)
/usr/home/JdeBP/b
/usr/home/JdeBP/a
/usr/home/JdeBP/b
% (cd b; pwd -P; /bin/pwd -P)
/usr/home/JdeBP/a
/usr/home/JdeBP/a
% (cd b; pwd -L; /bin/pwd -L)
/usr/home/JdeBP/b
/usr/home/JdeBP/b
% (cd -P b; pwd; /bin/pwd; printenv PWD)
/usr/home/JdeBP/a
/usr/home/JdeBP/a
/usr/home/JdeBP/a
% (cd b; PWD=/hello/there /bin/pwd -L)
/usr/home/JdeBP/a
% 

Relacionado:¿Busca un editor de archivos GUI alternativo con soporte para archivos grandes?

Como puede ver:obtener el directorio de trabajo "lógico" es cuestión de mirar el PWD variable de shell (o variable de entorno si no es el programa de shell); mientras que obtener el directorio de trabajo "físico" es cuestión de llamar a getcwd() función de biblioteca.

El funcionamiento del /bin/pwd programa cuando el -L se utiliza la opción es algo sutil. no se puede confiar el valor de la PWD variable de entorno que ha heredado. Después de todo, no es necesario que haya sido invocado por un shell y es posible que los programas que intervienen no hayan implementado el mecanismo del shell para hacer que el PWD La variable de entorno siempre realiza un seguimiento del nombre del directorio de trabajo. O alguien puede hacer lo que hice justo allí.

Entonces, lo que hace es (como dice el estándar POSIX) verificar que el nombre dado en PWD produce lo mismo que el nombre . , como se puede ver con un seguimiento de llamada del sistema:

% ln -s a c
% (cd b;  truss /bin/pwd -L 3>&1 1>&2 2>&3 | grep -E '^stat|__getcwd')
stat("/usr/home/JdeBP/b",{ mode=drwxr-xr-x ,inode=120932,size=2,blksize=131072 }) = 0 (0x0)
stat(".",{ mode=drwxr-xr-x ,inode=120932,size=2,blksize=131072 }) = 0 (0x0)
/usr/home/JdeBP/b
% (cd b; PWD=/usr/local/etc truss /bin/pwd -L 3>&1 1>&2 2>&3 | grep -E '^stat|__getcwd')
stat("/usr/local/etc",{ mode=drwxr-xr-x ,inode=14835,size=158,blksize=10240 }) = 0 (0x0)
stat(".",{ mode=drwxr-xr-x ,inode=120932,size=2,blksize=131072 }) = 0 (0x0)
__getcwd("/usr/home/JdeBP/a",1024)       = 0 (0x0)
/usr/home/JdeBP/a
% (cd b; PWD=/hello/there truss /bin/pwd -L 3>&1 1>&2 2>&3 | grep -E '^stat|__getcwd')
stat("/hello/there",0x7fffffffe730)      ERR#2 'No such file or directory'
__getcwd("/usr/home/JdeBP/a",1024)       = 0 (0x0)
/usr/home/JdeBP/a
% (cd b; PWD=/usr/home/JdeBP/c truss /bin/pwd -L 3>&1 1>&2 2>&3 | grep -E '^stat|__getcwd')
stat("/usr/home/JdeBP/c",{ mode=drwxr-xr-x ,inode=120932,size=2,blksize=131072 }) = 0 (0x0)
stat(".",{ mode=drwxr-xr-x ,inode=120932,size=2,blksize=131072 }) = 0 (0x0)
/usr/home/JdeBP/c
%

Como puede ver:solo llama a getcwd() si detecta un desajuste; y se puede engañar configurando PWD a una cadena que de hecho nombra el mismo directorio, pero por una ruta diferente.

El getcwd() función de la biblioteca es un tema por derecho propio. Pero para resumir:

  • Originalmente, era puramente una función de biblioteca, que construía un nombre de ruta desde el directorio de trabajo hasta la raíz al intentar repetidamente buscar el directorio de trabajo en el .. directorio. Se detuvo cuando llegó a un bucle donde .. era el mismo que su directorio de trabajo o cuando hubo un error al intentar abrir el siguiente .. arriba. Esto sería un montón de llamadas al sistema bajo las sábanas.
  • Hoy en día la situación es un poco más compleja. En FreeBSD, por ejemplo (esto también es válido para otros sistemas operativos), es una verdadera llamada al sistema, como puede ver en el seguimiento de la llamada al sistema dado anteriormente. Todo el recorrido desde el directorio de trabajo vnode hasta la raíz se realiza en una sola llamada al sistema, lo que aprovecha cosas como el acceso directo del código del modo kernel a la caché de entrada del directorio para realizar búsquedas de componentes de nombre de ruta de manera mucho más eficiente.

    Sin embargo, tenga en cuenta que incluso en FreeBSD y esos otros sistemas operativos el kernel no realizar un seguimiento del directorio de trabajo con una cadena.

Navegando a .. vuelve a ser un sujeto por derecho propio. Otro resumen:Aunque los directorios convencionalmente (aunque, como ya se mencionó, esto no requerido) contienen un .. real en la estructura de datos del directorio en el disco, el kernel rastrea el directorio principal de cada directorio vnode y, por lo tanto, puede navegar al .. vnode de cualquier directorio de trabajo. Esto es algo complicado por el punto de montaje y los mecanismos raíz modificados, que están más allá del alcance de esta respuesta.

Aparte

De hecho, Windows NT hace algo similar. Hay un solo directorio de trabajo por proceso, establecido por SetCurrentDirectory() Llamada API y seguimiento por proceso por parte del núcleo a través de un identificador de archivo abierto (interno) a ese directorio; y hay un conjunto de variables de entorno que Win32 programa (no solo los intérpretes de comandos, sino todos programas Win32) se utilizan para rastrear los nombres de varios directorios de trabajo (uno por unidad), agregándolos o sobrescribiéndolos cada vez que cambian de directorio.

Relacionado:¿Cómo usar $? y prueba para verificar la función?

Convencionalmente, a diferencia del caso de los sistemas operativos Unix y Linux, los programas Win32 no muestran estas variables de entorno a los usuarios. Sin embargo, a veces se pueden ver en subsistemas similares a Unix que se ejecutan en Windows NT, así como mediante el uso de SET de los intérpretes de comandos. comandos de una manera particular.

Lecturas adicionales

  • pwd “. Especificaciones básicas de Open Group Problema 7. IEEE 1003.1:2008. El Grupo Abierto. 2016.
  • “Resolución de nombre de ruta”. Especificaciones básicas de Open Group Problema 7. IEEE 1003.1:2008. El Grupo Abierto. 2016.
  • https://askubuntu.com/a/636001/43344
  • ¿Cómo se abren los archivos en Unix?
  • para qué sirve inode, en FreeBSD o Solaris
  • Extraña variable de entorno !::=::en Cygwin
  • ¿Por qué CDPATH no funciona como se documenta en los manuales?
  • ¿Cómo puedo configurar zsh para usar rutas físicas?
  • Ir a un directorio enlazado por un enlace

Linux
  1. Cómo mantener intactos los permisos de propiedad y archivo al copiar archivos o directorios

  2. Cómo encontrar el archivo más antiguo en un árbol de directorios en Linux

  3. Linux:¿cómo se inspecciona la información de la estructura del directorio de un archivo Unix/linux?

  4. ¿Cómo funciona el comando Exit en una terminal Unix?

  5. ¿Cómo funciona el comando 'ls' en Linux/Unix?

¿Cómo imprimir el directorio de trabajo usando el comando pwd de Linux?

cómo encontrar el propietario de un archivo o directorio en python

¿Cómo configuro el directorio de trabajo del proceso principal?

¿Cómo redirigir la salida de system() a un archivo?

¿Cómo obtengo el directorio absoluto de un archivo en bash?

¿Cómo puedo encontrar el archivo más antiguo en un árbol de directorios?