GNU/Linux >> Linux Esercitazione >  >> Linux

In che modo Unix tiene traccia della directory di lavoro di un utente durante la navigazione nel file system?

Supponiamo che io acceda a una shell su un sistema Unix e inizi a eliminare i comandi. Inizialmente inizio nella directory home del mio utente ~ . Potrei da lì cd fino alla directory Documents .

Il comando per cambiare directory di lavoro qui è molto semplice da capire intuitivamente:il nodo padre ha un elenco di nodi figli a cui può accedere e presumibilmente usa una variante (ottimizzata) di una ricerca per individuare l'esistenza di un nodo figlio con il nominare l'utente inserito e la directory di lavoro viene quindi "modificata" in modo che corrisponda a questo - correggimi se sbaglio lì. Potrebbe anche essere più semplice che la shell semplicemente "ingenuamente" tenti di accedere alla directory esattamente secondo i desideri dell'utente e quando il file system restituisce un qualche tipo di errore, la shell mostra una risposta di conseguenza.

Ciò che mi interessa, tuttavia, è come funziona lo stesso processo quando esploro una directory, ad esempio verso un genitore o il genitore di un genitore.

Data la mia posizione sconosciuta, presumibilmente "cieca" di Documents , una delle possibilmente molte directory nell'intero albero del file system con quel nome, in che modo Unix determina dove dovrei essere posizionato dopo? Fa riferimento a pwd ed esaminarlo? Se sì, come funziona pwd monitorare lo stato di navigazione corrente?

Risposta accettata:

Le altre risposte sono semplificazioni eccessive, ciascuna presenta solo parti della storia e sono sbagliate su un paio di punti.

Ce ne sono due modi in cui viene tracciata la directory di lavoro:

  • Per ogni processo, nella struttura dati dello spazio kernel che rappresenta quel processo, il kernel memorizza due riferimenti vnode ai vnode della directory di lavoro e alla directory root per quel processo. Il primo riferimento è impostato da chdir() e fchdir() chiamate di sistema, quest'ultimo da chroot() . Si possono vedere indirettamente in /proc su sistemi operativi Linux o tramite fstat comando su FreeBSD e simili:

    % 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
    % 

    Quando la risoluzione del percorso è attiva, inizia dall'uno o dall'altro di quei vnode di riferimento, a seconda che il percorso sia relativo o assoluto. (Esiste una famiglia di …at() chiamate di sistema che consentono alla risoluzione del percorso di iniziare nel vnode a cui fa riferimento un descrittore di file aperto (directory) come terza opzione.)

    Nel microkernel Unices la struttura dei dati è nello spazio delle applicazioni, ma il principio di mantenere i riferimenti aperti a queste directory rimane lo stesso.

  • Internamente, all'interno di shell come Z, Korn, Bourne Again, C e Almquist, la shell in aggiunta tiene traccia della directory di lavoro usando la manipolazione delle stringhe di una variabile stringa interna. Lo fa ogni volta che ha motivo di chiamare chdir() .

    Se si cambia in un percorso relativo, manipola la stringa per aggiungere quel nome. Se si cambia in un percorso assoluto, si sostituisce la stringa con il nuovo nome. In entrambi i casi, regola la stringa per rimuovere . e .. componenti e per inseguire i collegamenti simbolici sostituendoli con i loro nomi collegati. (Ecco il codice della shell Z per questo, ad esempio.)

    Il nome nella variabile stringa interna è tracciato da una variabile shell denominato PWD (o cwd nelle conchiglie C). Questo viene convenzionalmente esportato come una variabile di ambiente (denominata PWD ) ai programmi generati dalla shell.

Questi due metodi per tracciare le cose sono rivelati dal -P e -L opzioni al cd e pwd comandi incorporati della shell e dalle differenze tra pwd incorporata nelle shell comandi e sia il /bin/pwd comando e il pwd integrato comandi di cose come (tra gli altri) VIM e 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
% 

Correlati:Alla ricerca di un editor di file GUI alternativo con supporto per file di grandi dimensioni?

Come puoi vedere:ottenere la directory di lavoro “logica” è questione di guardare il PWD variabile shell (o variabile d'ambiente se non si tratta del programma shell); mentre per ottenere la directory di lavoro "fisica" si tratta di chiamare getcwd() funzione libreria.

Il funzionamento del /bin/pwd programma quando -L l'opzione è usata è alquanto sottile. non può fidarsi il valore del PWD variabile di ambiente che ha ereditato. Dopotutto, non è necessario che sia stato invocato da una shell e i programmi intermedi potrebbero non aver implementato il meccanismo della shell per creare il PWD la variabile di ambiente tiene sempre traccia del nome della directory di lavoro. Oppure qualcuno potrebbe fare quello che ho fatto io proprio lì.

Quindi quello che fa è (come dice lo standard POSIX) controllare che il nome dato in PWD restituisce la stessa cosa del nome . , come si può vedere con una traccia di chiamata di 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
%

Come puoi vedere:chiama solo getcwd() se rileva una mancata corrispondenza; e può essere ingannato impostando PWD a una stringa che in effetti denomina la stessa directory, ma con un percorso diverso.

Il getcwd() la funzione di biblioteca è un argomento a sé stante. Ma per la precisione:

  • In origine era puramente una funzione di libreria, che creava un percorso dalla directory di lavoro fino alla radice tentando ripetutamente di cercare la directory di lavoro nel .. directory. Si è fermato quando ha raggiunto un loop in cui .. era la stessa della sua directory di lavoro o quando si è verificato un errore durante il tentativo di aprire il successivo .. su. Sarebbero molte chiamate di sistema nascoste.
  • Oggi la situazione è leggermente più complessa. Su FreeBSD, per esempio (questo vale anche per altri sistemi operativi), è una vera chiamata di sistema, come puoi vedere nella traccia della chiamata di sistema fornita in precedenza. Tutto l'attraversamento dalla directory di lavoro vnode fino a root viene eseguito in una singola chiamata di sistema, che sfrutta cose come l'accesso diretto del codice in modalità kernel alla cache delle voci di directory per eseguire le ricerche dei componenti del percorso in modo molto più efficiente.

    Tuttavia, nota che anche su FreeBSD e quegli altri sistemi operativi il kernel non tieni traccia della directory di lavoro con una stringa.

Passando a .. è di nuovo un soggetto a sé stante. Un'altra precisazione:sebbene le directory convenzionalmente (sebbene, come già accennato, questo non richiesto) contengono un .. effettivo nella struttura dei dati della directory su disco, il kernel tiene traccia della directory padre di ciascuna directory vnode stessa e può quindi passare al .. vnode di qualsiasi directory di lavoro. Questo è in qualche modo complicato dal punto di montaggio e dai meccanismi di root modificati, che esulano dallo scopo di questa risposta.

A parte

Windows NT infatti fa una cosa simile. Esiste una singola directory di lavoro per processo, impostata da SetCurrentDirectory() Chiamata API e tracciata per processo dal kernel tramite un handle di file aperto (interno) in quella directory; e c'è un insieme di variabili d'ambiente che Win32 programma (non solo gli interpreti dei comandi, ma tutti Win32) utilizzano per tenere traccia dei nomi di più directory di lavoro (una per unità), aggiungendole o sovrascrivendole ogni volta che cambiano directory.

Correlati:come usare $? e prova per verificare la funzione?

Convenzionalmente, a differenza dei sistemi operativi Unix e Linux, i programmi Win32 non mostrano queste variabili di ambiente agli utenti. Tuttavia, a volte è possibile vederli in sottosistemi simili a Unix in esecuzione su Windows NT, nonché utilizzando il SET degli interpreti dei comandi comandi in un modo particolare.

Ulteriori letture

  • pwd “. Le specifiche di Open Group Base Edizione 7. IEEE 1003.1:2008. Il gruppo aperto. 2016.
  • "Risoluzione del percorso". Le specifiche di Open Group Base Edizione 7. IEEE 1003.1:2008. Il gruppo aperto. 2016.
  • https://askubuntu.com/a/636001/43344
  • Come vengono aperti i file in unix?
  • a cosa serve l'inode, in FreeBSD o Solaris
  • Strana variabile d'ambiente!::=::in Cygwin
  • Perché CDPATH non funziona come documentato nei manuali?
  • Come posso impostare zsh per utilizzare percorsi fisici?
  • Andare in una directory collegata da un link

Linux
  1. Come mantenere intatte la proprietà e le autorizzazioni dei file durante la copia di file o directory

  2. Come trovare il file più vecchio in un albero di directory in Linux

  3. Linux:con quale frequenza viene aggiornato il file system Proc su Linux?

  4. Come funziona il comando Exit su un terminale Unix?

  5. Come posso abilitare l'indicizzazione di file e directory Apache in Linux o UNIX?

Come stampare la directory di lavoro usando il comando pwd di Linux?

Come reindirizzare l'output di system() su un file?

Come ottengo la directory assoluta di un file in bash?

Come si esegue il gunzip di un file e si conserva il file .gz?

Spostare un file mentre è in uso:come funziona?

Qual è lo sticky bit nei file system UNIX? Quando viene utilizzato?