3

В ответ на вопрос, который я задал для SO:« Укажите точку монтирования пути», один респондент предложил использовать stat для получения имени устройства, связанного с томом данного пути. Это хорошо работает на Linux, но дает сумасшедшие результаты на Mac OS X 10.4. Для моей системы df и mount дают:

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)

Попытка получить устройства из точек монтирования, хотя:

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

Здесь я передаю каждую точку монтирования из df в stat, выводя результаты строки формата "% Sdr", которая должна быть именем устройства: Cf. Страница man 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.

В чем дело? Это ошибка в статистике, или какая-то странная дарвиновская VFS?

Постскриптум Эндрю МакГрегора, попробуйте передать "% Sd" в stat для большей странности. В нем перечислены некоторые явно произвольные подмножества файлов из CWD ...

3 ответа3

3

Во-первых, в качестве формата статистики «% Sdr» интерпретируется как селектор поля d , измененный спецификатором S , за которым следует буквальный символ R в нижнем регистре.

Возможно, справочная страница была бы более понятной, если бы она говорила «d, r» вместо "dr" в описании S d и r оба являются отдельными селекторами полей. r выбирает номер устройства из информации stat(2) (т. е. st_rdev; полезно только при статистике записей устройства (т. е. записей в /dev)). d выбирает номер устройства, на котором хранится запись (например, st_dev). Число, которое он печатает, представляет собой комбинацию старшего и младшего чисел, показанных ls (major << 24 | minor).

S - это модификатор, который может применяться как к d , r , так и к нескольким другим селекторам полей. При применении к d или r он пытается напечатать имя устройства вместо его необработанного номера. Некоторые устройства, такие как устройства с виртуальной файловой системой, не имеют собственных имен, поэтому он печатает ??? вместо этого (может быть лучше, если вместо этого будет напечатано <major>,<minor> ). Это не означает, что в этих файловых системах нет устройств, просто у их устройств нет обычных имен, таких как "disk0s3".

«Странность оболочки» («явно произвольное подмножество файлов из CWD») связана с отсутствием цитирования. Оболочка видит (без кавычек) "???"результат и расширяет его как шаблон глобуса. Если cwd содержит какие-либо записи с ровно тремя байтами (символами, в зависимости от локали?), Оболочка заменит эти записи шаблоном glob. Поведение (цитирование и расширение glob) зависит от оболочки и обычно может быть изменено с помощью различных параметров оболочки.

Вы можете изменить свою исходную команду следующим образом, чтобы избежать сбоев и запаздывания "r":

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

Но я бы написал это так:

df | tail +2 | awk '{print $NF}' | xargs stat -f'%N %Sd %d'
  • Обратите внимание, что это не работает для любых смонтированных файловых систем с пробелами в именах точек монтирования. Ни выходы mount, ни df не могут быть легко проанализированы (оба имеют поля, в которых могут быть почти произвольные строки).

С этим выводом (имя, номер устройства, имя устройства), вы можете получить лучшее представление о том, что происходит.

Или, может быть, вы хотели бы видеть старшие и младшие номера в дополнение к необработанным номерам устройств (сравните их с тем, что вы видите (например, в 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'

Вот небольшая программа на C, которая может заменить проблемный конвейер "df | head | awk".

Конечно, такая программа на C могла бы выполнять остальную работу сама, но было бы неплохо иметь отдельную программу, которая может просто выплевывать NUL-завершенные точки монтирования.

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

Код:

#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);
    }
}
1

Таким образом, у виртуальных файловых систем нет устройств - я не пробовал это для этих файловых систем. Это не проблема для /Network, /automount /Servers или /automount /static, так как они не должны содержать файлы. Но /dev это интересно.

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

Я бы сказал, Дарвин VFS странность.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .