la ricerca PATH include collegamenti simbolici?


9

Lo standard shell POSIX dice su questo sito

http://pubs.opengroup.org/onlinepubs/9699919799/

su come le shell usano PATHper cercare gli eseguibili:

"L'elenco deve essere cercato dall'inizio alla fine, applicando il nome file a ciascun prefisso, fino a quando non viene trovato un file eseguibile con il nome specificato e le autorizzazioni di esecuzione appropriate."

Bene, non è così che sembra funzionare nell'implementazione POSIX reale:

man which dice:

"restituisce i percorsi dei file (o collegamenti) che verrebbero eseguiti nell'ambiente attuale, se i suoi argomenti fossero dati come comandi in una shell strettamente conforme a POSIX. Lo fa cercando nel PERCORSO i file eseguibili che corrispondono ai nomi dei argomenti. Non segue collegamenti simbolici ".

OK, diamo un'occhiata a questa situazione:

$ pwd /home/mark

$ echo $PATH /home/mark/bin:...

$ ls -l bin/foobar
lrwxrwxrwx 1 mark mark 18 Dec 12 22:51 bin/foobar -> /home/mark/foobar1
$ touch foobar1
$ which foobar
$ chmod a+x foobar1
$ which foobar
/home/mark/bin/foobar

OK, qui c'è un link simbolico PATHcon il nome corretto e viene segnalato lscome eseguibile.

which non lo guarda affatto, ma è interessato solo a ciò a cui punta.

Ciò nonostante il fatto che entrambi man whichaffermino esplicitamente che non segue collegamenti simbolici (e in effetti lo vediamo non, perché which foobarnon stampa foobar1), e anche che la documentazione della shell POSIX citata sopra, non menziona mai i seguenti collegamenti simbolici PATHnell'algoritmo.

Quindi, whichle shell esistenti sono sbagliate o non capisco la documentazione?

CHIARIRE:

Conosco e posso spiegare il comportamento esistente. La mia domanda non è "come funziona?". Questo lo so.

La mia domanda riguarda la documentazione: dov'è il mio errore nel seguire la documentazione che ho citato. O la documentazione è sbagliata?

MOTIVAZIONE: Perché me ne importa?

Bene, sono un implementatore. Diversi implementatori hanno requisiti diversi. Per me, il requisito è che la parola dell'attuale standard POSIX DEVE essere seguita ESATTAMENTE (o, più precisamente, il meglio che può essere, perché lo standard stesso è in qualche modo difettoso). Come fosse la parola di Dio.

Ora, la formulazione standard è abbastanza chiara: i seguenti collegamenti simbolici non sono menzionati, dove in molti altri luoghi, è menzionato dove deve essere fatto. Quindi, in questo caso, non farlo.

Tuttavia, ricontrollo sempre come dashe come mi bashcomporto, per essere sicuro. Ora, ovviamente, c'è anche un piccolo problema qui, dashanche se è fatturato come POSIX, ha molti piccoli bug con conformità a POSIX. bash, Non ho ancora trovato alcun bug con POSIX, ma ... bash non è in realtà POSIX, è molto di più.

Così il gioco è fatto. Ecco perché mi interessa.


Non capisci: che non segue i collegamenti simbolici sui file . $PATHcan contiene collegamenti simbolici. Prova which sh.
Ipor Sircer,

OK ma, nel mio caso $PATH, non ha collegamenti simbolici.
user322908

In quasi tutte le situazioni, i collegamenti simbolici vengono seguiti in modo trasparente. I casi in cui non lo sono vengono di solito menzionati esplicitamente (ad es. Chiamate di sistema simili lstat(2)), di seguito non viene generalmente indicato. Ad esempio, la descrizione di open(2)menziona solo i link simbolici quando si parla del comportamento di O_CREAT | O_EXCL. Non è necessario indicare che il file di destinazione verrà aperto.
Barmar,

Risposte:


10

Le autorizzazioni del link simbolico stesso sono irrilevanti. Non potresti nemmeno cambiarli se ci provassi.

Ciò che conta sono le autorizzazioni del file sottostante.

È bene che le directory nel PATH includano collegamenti simbolici agli eseguibili. In effetti, è probabile che molti file eseguibili nel tuo PERCORSO siano collegamenti simbolici. Ad esempio, su sistemi simili a debian / ubuntu:

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Jan 23  2017 /bin/sh -> dash

Documentazione

Da man chmod:

chmod non cambia mai le autorizzazioni dei collegamenti simbolici; la chiamata di sistema chmod non può cambiare le loro autorizzazioni. Questo non è un problema poiché le autorizzazioni dei collegamenti simbolici non vengono mai utilizzate. Tuttavia, per ogni collegamento simbolico elencato nella riga di comando, chmod modifica le autorizzazioni del file puntato. Al contrario, chmod ignora i collegamenti simbolici incontrati durante gli attraversamenti ricorsivi di directory. [Enfasi aggiunta.]

Esempio

La shell ha un test, -xper determinare se un file è eseguibile. Proviamo che:

$ ls -l
total 0
lrwxrwxrwx 1 john1024 john1024 7 Dec 12 23:36 foo -> foobar1
-rw-rw---- 1 john1024 john1024 0 Dec 12 23:36 foobar1
$ [ -x foo ] && echo foo is executable
$ chmod +x foobar1
$ [ -x foo ] && echo foo is executable
foo is executable

Quindi, proprio come hai trovato con which, la shell non considera un eseguibile di softlink a meno che il file sottostante non sia eseguibile.

Come funziona

Su un sistema Debian, whichè uno script di shell. La sezione pertinente del codice è:

 case $PROGRAM in
  */*)
   if [ -f "$PROGRAM" ] && [ -x "$PROGRAM" ]; then
    puts "$PROGRAM"
    RET=0
   fi
   ;;
  *)
   for ELEMENT in $PATH; do
    if [ -z "$ELEMENT" ]; then
     ELEMENT=.
    fi
    if [ -f "$ELEMENT/$PROGRAM" ] && [ -x "$ELEMENT/$PROGRAM" ]; then
     puts "$ELEMENT/$PROGRAM"
     RET=0
     [ "$ALLMATCHES" -eq 1 ] || break
    fi
   done
   ;;
 esac

Come puoi vedere, utilizza il -xtest per determinare se un file è eseguibile.

POSIX specifica il -xtest come segue:

-x nome percorso
Vero se il nome percorso viene risolto in una voce di directory esistente per un file per il quale verrà concessa l' autorizzazione per eseguire il file (o cercarlo, se è una directory), come definito in Lettura, scrittura e creazione del file. Falso se il nome percorso non può essere risolto o se il nome percorso si risolve in una voce di directory esistente per un file per il quale l'autorizzazione per eseguire (o cercare) il file non verrà concessa. [Enfasi aggiunta.]

Quindi, POSIX controlla a cosa si risolve il nome percorso . In altre parole, accetta collegamenti simbolici.

Funzione exec POSIX

La funzione exec POSIX segue collegamenti simbolici. Le specifiche POSIX vanno avanti per specificare le condizioni di errore che potrebbero segnalare se i collegamenti simbolici sono circolari o troppo profondi, come:

[ELOOP] Esiste
un ciclo nei collegamenti simbolici rilevati durante la risoluzione del percorso o dell'argomento file.

[ELOOP]
Durante la risoluzione del percorso o dell'argomento file sono stati rilevati più di {SYMLOOP_MAX} collegamenti simbolici.
[ENAMETOOLONG]
Come risultato dell'incontro con un collegamento simbolico nella risoluzione dell'argomento del percorso, la lunghezza della stringa del percorso sostituita ha superato {PATH_MAX}.


CONOSCO tutto ciò che hai scritto nella tua risposta. So come funzionano le cose. Questa non è la mia domanda. La mia domanda riguarda la documentazione. Indicami dove non capisco la documentazione. O dimmi che la documentazione non è corretta.
user322908

@ user322908 Sulla maggior parte dei sistemi, whichè uno script di shell. Pertanto, è probabile che stia semplicemente usando il -xtest che ho mostrato. Secondo POSIX, -xverifica se un file "si risolve" in un eseguibile. Se vedi qualcosa di diverso, dove stai guardando?
Giovanni 1024

Grazie e mi dispiace di essere un tale dolore ... Mi rendo conto che la mia domanda è diversa dal 99% delle domande, quindi è difficile capire cosa sto cercando. Ancora una volta, non mi interessa "come" whichfunziona, se è -xo qualcos'altro. Sono interessato a sapere dove non sto seguendo correttamente la documentazione che ho citato.
user322908,

4
@ user322908 La funzione POSIXexec segue collegamenti simbolici. Ciò sembra chiarire che i file con link simbolici possono essere eseguibili in POSIX.
Giovanni 1024,

2
Ho anche controllato Ubuntu 17.10 man which che dice "Non canonicalizza i nomi dei percorsi". Ciò non significa che non segua i collegamenti. Ciò significa solo, come hai osservato, che non "canonicalizza" i nomi.
Giovanni 1024,

3

In questo caso i symlink vengono seguiti in modo trasparente, senza canonicalizzare il percorso finale. In altre parole, whichnon importa se si /home/mark/bintratta di un collegamento simbolico o meno. Ciò che importa è se il file /home/mark/bin/foobaresiste o no. Non è necessario appiattire manualmente i collegamenti simbolici lungo il percorso: il sistema operativo può farlo da solo.

E infatti, quando whichchiede informazioni sui file di /home/mark/bin/foobar, il sistema operativo nota che /home/mark/binè un collegamento simbolico, lo segue e trova correttamente foobarnella directory di destinazione.

Questo è il comportamento predefinito a meno che il programma non utilizzi open(…, O_NOFOLLOW)o fstatat(…, AT_SYMLINK_NOFOLLOW)per accedere al file.

[commenti uniti]

Mentre si dice che le utility shell lo fanno su una base caso per caso, non è la stessa cosa con kernel syscalls: tutte le chiamate relative ai file fanno seguire i link simbolici per impostazione predefinita, a meno che non viene dato il flag "nofollow". (Anche lstat segue i collegamenti simbolici in tutti i componenti del percorso tranne l'ultimo.)

Quando la specifica non menziona esplicitamente cosa fare con i collegamenti simbolici, implica che verrà utilizzato il comportamento predefinito. Cioè, una shell che segue l'algoritmo del percorso non risolve manualmente i symlink esplicitamente rinuncia al SO facendo lo stesso. (Concatena solo ogni componente $ PATH con il nome dell'eseguibile.)

Quando la pagina del manuale who (1) dice che non segue i symlink, può significare diverse cose, ma la versione GNU coreutils lo afferma in questo modo:

Che considererà due directory equivalenti diverse quando una contiene un percorso con un collegamento simbolico.

Ciò ha una portata molto più ristretta: significa solo whichche non tenterà di canonicalizzare manualmente tutti i percorsi per eliminare i duplicati, ma non implica che lo strumento disattiverà il collegamento simbolico seguito dal sistema operativo in generale. Ad esempio, se /binè un collegamento simbolico a /usr/bin, l'esecuzione which -a shrestituirà sia /bin/sh e /usr/bin/sh.


Sì grazie, lo so tutto questo. La mia domanda non è come le cose "funzionano". So come funzionano. Non è questo il punto. Il mio punto è sulla documentazione. Dove sto seguendo la documentazione in modo errato. O la documentazione non è corretta.
user322908

2
Comprendi la documentazione in modo errato - se non menziona i seguenti collegamenti simbolici, ciò significa che non risolve manualmente i collegamenti simbolici, ma si applica comunque il normale comportamento del sistema operativo . La whichpagina del manuale GNU lo afferma in modo diverso: "Che considererà due directory equivalenti diverse quando una di esse contiene un percorso con un collegamento simbolico".
user1686

OK, meglio grazie! Sto cercando di capire ... Ma ... scusa se sono un dolore al collo: "il normale comportamento del sistema operativo" NON è sempre seguire implicitamente i link simbolici. Ci sono molte utility che non lo fanno. È caso per caso.
user322908

1
Tutte le chiamate del kernel - chdir, open, chmod, execve ... - seguiranno i collegamenti simbolici sia nel percorso che nella coda, a meno che non si specifichi AT_SYMLINK_NOFOLLOW o simile. (lstat è l'unico che non dereferenzia collegamenti simbolici alla coda, ma lo fa comunque per il percorso rimanente.) Pertanto il comportamento predefinito è seguire i collegamenti simbolici. Ad esempio, quando una shell chiama execve("/home/mark/bin/foobar", …), si verifica che tutti i collegamenti simbolici vengano seguiti.
user1686

OK, penso che sto acquistando l' execveargomento, in realtà, nella mia implementazione, è la execl()stessa cosa. Per favore, se lo includi nella tua risposta, accetterò.
user322908

1

La shell è conforme alla sua documentazione in quanto segue le regole per la risoluzione del percorso. whichè conforme alla sua documentazione. I due fanno cose leggermente diverse.

L'output di whichè il nome e il percorso del file del collegamento, non il percorso a cui punta il collegamento simbolico. Questo è spiegato nella pagina man.

Quando viene eseguito un comando, il collegamento viene "seguito" di cui alla Sezione 4.13 Pathname risoluzione nella stessa . La clausola rilevante per l'esecuzione di un file è:

In tutti gli altri casi, il sistema deve aggiungere il prefisso rimanente, se presente, con il contenuto del collegamento simbolico, tranne per il fatto che se il contenuto del collegamento simbolico è la stringa vuota, allora la risoluzione del percorso deve fallire con le funzioni che riportano un [ENOENT ] errore e utilità che scrivono un messaggio diagnostico equivalente o il percorso della directory contenente il collegamento simbolico deve essere utilizzato al posto del contenuto del collegamento simbolico. Se il contenuto del collegamento simbolico è costituito esclusivamente da caratteri, tutti i caratteri iniziali del percorso rimanente devono essere omessi dal percorso combinato risultante, lasciando solo i caratteri iniziali dal contenuto del collegamento simbolico. Nei casi in cui si verifica il prefisso, se la lunghezza combinata supera {PATH_MAX} e l'implementazione ritiene che si tratti di un errore, la risoluzione del percorso deve fallire con le funzioni che riportano un errore [ENAMETOOLONG] e le utilità che scrivono un messaggio diagnostico equivalente. Altrimenti, il percorso risolto deve essere la risoluzione del percorso appena creato. Se il percorso risultante non inizia con a, il predecessore del primo nome file del percorso viene considerato la directory contenente il collegamento simbolico.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.