Controlla se 2 directory sono ospitate sulla stessa partizione su Linux


9

Come posso verificare se si /my/dirtrova sulla stessa partizione di /?

Questo è per l'integrazione all'interno di uno script. I supporti di collegamento devono essere gestiti correttamente. Le soluzioni compatibili POSIX sono benvenute.


"I supporti di collegamento devono essere gestiti correttamente." Ma cosa ritieni corretto? La tua domanda può essere interpretata in entrambi i modi.
Gilles 'SO- smetti di essere malvagio' il

@Gilles Nel titolo originale ho scritto "ospitato" anziché "montato", qualcuno ha modificato aggiungendo confusione IMHO. Eppure il mio corpo di domanda è chiaro: "sulla stessa partizione", cioè sulla stessa partizione fisica, qualunque sia il percorso o il mountpoint utilizzato per accedere ai due file / directory.
Totor

Risposte:


6

Puoi verificarlo con stat:

$ stat -c '%d %m' /proc/sys/
3 /proc

Ti mostra il numero del dispositivo e dove è stata montata la tua directory.


1
Bello, ma il statcomando shell non è POSIX ...
Totor

No? Come lo sai?

Non in questo elenco .
Totor

Oh mio Dio. Ma la prossima volta mostra questo link in anticipo.

5

Il comando seguente fornisce un nome univoco per il punto di montaggio contenente il file $file:

df -P -- "$file" | awk 'NR==2 {print $1}'

Funziona su qualsiasi sistema POSIX . L' -Popzione impone un formato prevedibile; il primo campo della seconda riga è il "nome del file system". Pertanto, per controllare due file si trovano nello stesso punto di montaggio:

if [ "$(df -P -- "$file1" | awk 'NR==2 {print $1}')" = \
     "$(df -P -- "$file2" | awk 'NR==2 {print $1}')" ]; then
  echo "$file1 and $file2 are on the same filesystem" ; fi

Oppure, per salvare un paio di invocazioni di processo:

if df -P -- "$file1" "$file2" |
   awk 'NR!=1 {dev[NR] = $1} END {exit(dev[2] != dev[3])}'; then
  echo "$file1 and $file2 are on the same filesystem" ; fi

Alcuni sistemi operativi possono avere spazi nei nomi dei volumi. In dfquesto caso non esiste un modo completamente affidabile per analizzare l' output.

Sotto il cofano, puoi identificare il filesystem contenente un file dal st_devcampo restituito da stat. Non esiste un modo portatile per farlo da uno script di shell. Alcuni sistemi hanno statun'utilità, ma la sua sintassi varia:

  • Su Linux non embedded, Cygwin o altri sistemi con core GNU GNU, statsegnala il st_devcampo quando invocato come stat -c %D -- "$file".
  • Alcune installazioni di BusyBox includono una statcompatibile con i coreutils GNU. Altri hanno statsenza l' %copzione; puoi usarlo, stat -t -- "$file" | awk '{print $8}'ma funziona solo se il nome del file non contiene spazi bianchi o se fa stat -t -- "$file" | awk 'END {print $(NF-8)}'fronte a nomi di file arbitrari ma non con future aggiunte di campi statall'output.
  • I sistemi BSD hanno statun'utilità diversa che richiede stat -f %d -- "$file".
  • Solaris, AIX e altri non hanno statutilità.

Se Perl è disponibile, è possibile utilizzare

perl -e 'print ((stat($ARGV[0]))[0])' -- "$file"

e per fare il confronto:

perl -e 'exit((stat($ARGV[0]))[0] != (stat($ARGV[1]))[0])' -- "$file1" "$file2"

Si noti che ci sono alcuni casi angolari in cui il risultato desiderato non è chiaro. Ad esempio, con supporti bind di Linux, dopo mount --bind /foo /bar, /fooe /barsono considerati lo stesso file system. È sempre possibile che i due file si trovino effettivamente sullo stesso dispositivo, ma non lo saprai mai: ad esempio, se i file si trovano su due diversi montaggi di rete, il client non ha modo di sapere se il server sta esportando file system diversi.

Se i file sono directory e puoi scriverli, un altro metodo è quello di creare un file temporaneo e tentare di creare un collegamento reale. Questo riporta un risultato negativo su tutti i mount bind di Linux.

tmp1=$(TMPDIR=$dir1 mktemp)
tmp2=$(TMPDIR=$dir2 mktemp)
if ln -f -- "$tmp1" "$tmp2"; then
  echo "$dir1 and $dir2 are on the same filesystem, which supports hard links"
fi
rm -f "$tmp1" "$tmp2"

Problema: dfnon sempre fornisce il nome del dispositivo, ma a volte un link simbolico ad esso non /dev/disk/by-uuid/ca09b761-ae1b-450f-8a46-583327b48fb4rende dfaffidabile. L'unica opzione affidabile finora è l'utilizzo di una statsoluzione basata su.
Totor

@Totor Non importa: qualunque sia il nome dfriportato per il dispositivo, è coerente tra le due invocazioni, quindi va bene per un confronto.
Gilles 'SO- smetti di essere cattivo' il

No, non funziona, l'ho provato. Su Debian Wheezy qui, un singolo dfreport /dev/sda6e /dev/disk/by-uuid/ca09b..., entrambi riferiti allo stesso dispositivo, ma punti di mount diversi. Il test di confronto delle stringhe ovviamente fallisce quando si prova con file da ciascun punto di montaggio.
Totor

@Totore Normalmente non è possibile montare lo stesso dispositivo a blocchi due volte. Come indico nella mia risposta, ci sono casi angolari come attacchi di associazione che possono essere o meno segnalati come distinti.
Gilles 'SO- smetti di essere malvagio' il

Tuttavia funziona perfettamente su Debian Squeeze e Wheezy: mount /dev/sda6 /mnt1seguito da mount /dev/sda6 /mnt2opere come un fascino. cat /proc/mountsva bene con esso. Tuttavia, è solo da Wheezy che /dev/disk/by-uuid/ca09b...viene mostrato dfcome dispositivo per il filesystem di root. Ulteriori tentativi di montarlo usando questo simlink o la UUID=ca09b...sintassi del mount non finiscono per mostrare nient'altro che /dev/sda6in df(non so come riprodurre ciò che ha fatto durante il processo di avvio, ma non è questo il problema).
Totor

4
test $(df -P $path1 $path2 | awk '{if (NR!=1) {print $6}}' | uniq | wc -l) -eq 1

Funziona con qualsiasi numero di percorsi.


Analizzare l'output di nondf è sempre una buona idea .
Joseph R.

1
@Totor Sto verificando il mountpoint ( $6), non il nome del dispositivo ( $1), quindi non dovrebbe essere un problema.
n.

1
@JosephR È il migliore che ci sia in POSIX. n.st: perché non controllare il primo campo? Non importa quale percorso è stato utilizzato per accedere al dispositivo, se è lo stesso punto di montaggio, l'output sarà coerente.
Gilles 'SO-smetti di essere malvagio' il

Questo non funziona con gli attacchi bind.
Totor

0

La migliore soluzione infallibile disponibile in POSIX è il confronto degli ID dispositivo dei file forniti dalla funzione stat (2) .

Perl ha una funzione statistica simile a quella indicata da Gilles :

perl -e 'exit((stat($ARGV[0]))[0] != (stat($ARGV[1]))[0])' -- file1 file2

ma il "modo POSIX" è usare un programma C come:

./checksamedev file1 file2

quale codice sorgente è il seguente:

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char* argv[]) {
    struct stat s1, s2;
    if( argc==3 && lstat(argv[1], &s1)==0 && lstat(argv[2], &s2)==0 )
        return !(s1.st_dev == s2.st_dev);
    return 2;
}

Se gli ID dispositivo di entrambi i file sono uguali, sono ospitati sullo stesso filesystem, nel qual caso i comandi sopra restituiscono 0 (un altro valore altrimenti). Verificare con echo $?.

Funziona bene con i montaggi di bind, ma probabilmente non con i montaggi di rete.

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.