Шрифт:
#include <sys/types.h> /* Обычный */
#include <sys/sysmacros.h>
int major(dev_t dev); /* Старший номер устройства */
int minor(dev_t dev); /* Младший номер устройства */
dev_t makedev(int major, int minor); /* Создать значение dev_t */
(Некоторые системы реализуют их в виде макросов.)
Функция
makedev
идет другим путем; она принимает отдельные значения старшего и младшего номеров и кодирует их в значении dev_t
. В других отношениях ее использование выходит за рамки данной книги; патологически любопытные должны посмотреть mknod(2). Следующая программа,
ch05-devnum.c
, показывает, как использовать системный вызов stat
, макросы проверки типа файла и, наконец, макросы major
и minor
.
/* ch05-devnum.c --- Демонстрация stat, major, minor. */
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
int main(int argc, char **argv) {
struct stat sbuf;
char *devtype;
if (argc != 2) {
fprintf(stderr, "usage: %s path\n", argv[0]);
exit(1);
}
if (stat(argv[1], &sbuf) < 0) {
fprintf(stderr, "%s: stat: %s\n", argv[1], strerror(errno));
exit(1);
}
if (S_ISCHR(sbuf.st_mode))
devtype = "char";
else if (S_ISBLK(sbuf.st_mode))
devtype = "block";
else {
fprintf(stderr, "%s is not a block or character device\n",
argv[1]);
exit(1);
}
printf("%s: major: %d, minor: %d\n", devtype,
major(sbuf.st_rdev), minor(sbuf.st_rdev));
exit(0);
}
Вот что происходит при запуске программы:
$ ch05-devnum /tmp /* Попробовать не устройство */
/tmp is not a block or character device
$ ch05-devnum /dev/null /* Символьное устройство */
char: major: 1, minor: 3
$ ch05-devnum /dev/hda2 /* Блочное устройство */
block: major: 3, minor: 2
К счастью, вывод согласуется с выводом
ls
, давая нам уверенность [59] , что мы в самом деле написали правильный код. Воспроизведение вывода ls замечательно и хорошо, но действительно ли это полезно? Ответ — да. Любое приложение, работающее с иерархиями файлов, должно быть способно различать различные типы файлов. Подумайте об архиваторе, таком как
tar
или cpio
. Было бы пагубно, если бы такая программа рассматривала файл дискового устройства как обычный файл, пытаясь прочесть его и сохранить его содержимое в архиве! Или подумайте о find
, которая может выполнять произвольные действия, основываясь на типе и других атрибутах файлов, с которыми она сталкивается, (find
является сложной программой; посмотрите find(1), если вы с ней не знакомы.) Или даже нечто простое, как пакет, оценивающий свободное дисковое пространство, тоже должно отличать обычные файлы от всего остального.59
Технический термин warm fuzzy — Примеч. автора.
5.4.4.2. Возвращаясь к V7
cat
В разделе 4.4.4 «Пример: Unix cat» мы обещали вернуться к программе V7
cat
, чтобы посмотреть, как она использует системный вызов stat
. Первая группа строк, использовавшая ее, была такой:
31 fstat(fileno(stdout), &statb);
32 statb.st_mode &= S_IFMT;
33 if (statb.st_mode != S_IFCHR && statb.st_mode != S_IFBLK) {
34 dev = statb.st_dev;
35 ino = statb.st_ino;
36 }
Этот код теперь должен иметь смысл. В строке 31 вызывается
fstat
для стандартного вывода, чтобы заполнить структуру statb
. Строка 32 отбрасывает всю информацию в statb.st_mode
за исключением типа файла, используя логическое AND с маской S_IFMT
. Строка 33 проверяет, что используемый для стандартного вывода файл не является файлом устройства. В таком случае программа сохраняет номера устройства и индекса в dev
и ino
. Эти значения затем проверяются для каждого входного файла в строках 50–56.