O que há com o stat no Mac OS X / Darwin? Ou sistemas de arquivos sem nomes

3

Em resposta a uma pergunta que fiz em SO, dê o ponto de montagem de um caminho , um respondente sugeriu usar stat para obter o nome do dispositivo associado ao volume de um determinado caminho. Isso funciona muito bem no Linux, mas dá resultados loucos no Mac OS X 10.4. Para o meu sistema, df e mount dão:

cas cas$ df
Filesystem              512-blocks     Used     Avail Capacity  Mounted on
/dev/disk0s3              58342896 49924456   7906440    86%    /
devfs                          194      194         0   100%    /dev
fdesc                            2        2         0   100%    /dev
<volfs>                       1024     1024         0   100%    /.vol
automount -nsl [166]             0        0         0   100%    /Network
automount -fstab [170]           0        0         0   100%    /automount/Servers
automount -static [170]          0        0         0   100%    /automount/static
/dev/disk2s1             163577856 23225520 140352336    14%    /Volumes/Snapshot
/dev/disk2s2             409404102  5745938 383187960     1%    /Volumes/Sparse
cas cas$ mount
/dev/disk0s3 on / (local, journaled)
devfs on /dev (local)
fdesc on /dev (union)
<volfs> on /.vol
automount -nsl [166] on /Network (automounted)
automount -fstab [170] on /automount/Servers (automounted)
automount -static [170] on /automount/static (automounted)
/dev/disk2s1 on /Volumes/Snapshot (local, nodev, nosuid, journaled)
/dev/disk2s2 on /Volumes/Sparse (asynchronous, local, nodev, nosuid)

Tentando obter os dispositivos dos pontos de montagem, no entanto:

cas cas$ df | grep -e/ 
            | awk '{print $NF}' 
            |  while read line; do echo $line $(stat -f"%Sdr" $line); done
/ disk0s3r
/dev ???r
/dev ???r
/.vol ???r
/Network ???r
/automount/Servers ???r
/automount/static ???r
/Volumes/Snapshot disk2s1r
/Volumes/Sparse disk2s2r

Aqui, estou alimentando cada um dos pontos de montagem extraídos de df para stat , exibindo os resultados do "% Sdr" formato string, que é suposto ser o nome do dispositivo: Cf. Página man do stat (1):

The special output specifier S may be used to indicate that the
output, if applicable, should be in string format.  May be used
in combination with:
...
             dr      Display actual device name.

O que está acontecendo? É um bug em stat , ou alguma estranheza do Darwin VFS?

Postscript Por Andrew McGregor, tente passar "% Sd" para stat para mais estranheza. Ele lista alguns subconjuntos aparentemente arbitrários de arquivos do CWD ...

    
por Charles Stewart 02.02.2010 / 11:40

3 respostas

3

Primeiro, como um formato stat , "% Sdr" é interpretado como o seletor de campo d , modificado pelo especificador S , seguido por um caractere literal de letra minúscula. / p>

A manpage provavelmente seria mais clara se dissesse "d, r" em vez de "dr" sob a descrição de S . d e r são ambos seletores de campo separados. r seleciona o número do dispositivo a partir da informação stat (2) (isto é, st_rdev; útil apenas para entradas de dispositivos estatísticos (ou seja, as entradas em / dev)). d seleciona o número do dispositivo que contém a entrada da estatística (ou seja, st_dev). O número impresso é uma combinação dos números principal e secundário mostrados por ls (maior <| menor |)

S é um modificador que pode ser aplicado a d , r e vários outros seletores de campo. Quando aplicado a d ou r , ele tenta imprimir o nome do dispositivo em vez de seu número bruto. Alguns dispositivos, como os dispositivos do sistema de arquivos virtual, não possuem nomes próprios, portanto, imprime ??? (pode ser melhor se ele imprimiu <major>,<minor> ). Isso não significa que esses sistemas de arquivos não possuam dispositivos, apenas que seus dispositivos não possuem nomes normais como "disk0s3".

A "estranheza do shell" ("subconjunto aparentemente arbitrário de arquivos do CWD") é devido à falta de cotação. O shell vê o (sem aspas) "???" resultar e expande-lo como um padrão glob. Se o cwd contiver alguma entrada com exatamente três bytes (caracteres, dependendo da localidade?), O shell substituirá essas entradas pelo padrão glob. O comportamento (a cotação e a expansão glob) varia por shell e geralmente pode ser modificado por várias opções de shell.

Você pode modificar seu comando original assim para evitar a globbing e o "r":

df | grep -e/ | awk '{print $NF}' |  while read line; do echo "$line" "$(stat -f%Sd "$line"); done

Mas eu provavelmente escreveria assim:

df | tail +2 | awk '{print $NF}' | xargs stat -f'%N %Sd %d'
  • Observe que isso falha para que qualquer sistema de arquivos montado tenha espaços em seus nomes de ponto de montagem. Nem a saída de mount ou df é super fácil de analisar prontamente (ambos têm campos que podem ter sequências quase arbitrárias neles).

Com essa saída (nome, número do dispositivo, nome do dispositivo), talvez você possa ter uma ideia melhor do que está acontecendo.

Ou talvez você queira ver os números principais e secundários além dos números de dispositivos brutos (compare com o que você vê em (por exemplo) ls -l /dev/disk0s3 ):

df | tail +2 | awk '{print $NF}' | xargs stat -f'%N %Sd %d' | 
  awk 'BEGIN{f=2^24} {$(NF+1) = int($NF/f) "," ($NF%f) } 1'

Aqui está um pequeno programa em C que pode substituir o pipeline problemático "df | head | awk".

Naturalmente, esse programa em C pode fazer o resto funcionar sozinho, mas pode ser bom ter um programa autônomo que possa simplesmente criar pontos de montagem terminados em NUL.

mountz | xargs -0 stat -f'%N %Sd %d' | 
  awk 'BEGIN{f=2^24} {$(NF+1) = int($NF/f) "," ($NF%f) } 1'

Código:

#include <sys/mount.h>
#include <stdio.h>
#include <stdlib.h>

/* usage: mountz | xargs -0 command_for_each_mount_point */

int main(int argc, const char *argv[]) {
    struct statfs *buf;
    int flags = MNT_NOWAIT, num_fs, num_stat, i;
    unsigned bufsz;

    num_fs = getfsstat(NULL, 0, flags);
    if (num_fs < 0) {
        perror("unable to count mounted filesystems: getfsstat");
    exit(1);
    }

    bufsz = sizeof(*buf) * num_fs;
    buf = malloc(bufsz);
    if (!buf) {
        perror("unable to allocate %u statfs structs");
    exit(1);
    }
    fprintf(stderr, "p=%p\n", buf);

    num_stat = getfsstat(buf, bufsz, flags);
    if (num_stat < 0) {
        perror("unable to getfsstat");
    exit(1);
    }
    if (num_stat != num_fs) {
    fprintf(stderr, "Hmm, expected %u, got %d.\n", num_fs, num_stat);
    }

    for (i = 0; i < num_stat; i++) {
    fprintf(stdout, "%s%c", buf[i].f_mntonname, 0);
    }
}
    
por 18.03.2010 / 21:34
1

Assim, os sistemas de arquivos virtuais não têm dispositivos - não tentei para esses sistemas de arquivos. Não é um problema para / Network, / automount / Servers ou / automount / static, pois não devem conter arquivos. Mas / dev é interessante.

    
por 02.02.2010 / 12:16
1
df | grep -e/ | awk '{print $NF}' |  while read line; do echo $line $(stat -f"%Sd" $line); done
/ disk0s2
/dev XGS bin tmp
/net XGS bin tmp
/home XGS bin tmp

Eu diria, estranheza de Darwin VFS.

    
por 02.02.2010 / 12:17