一、主、次设备号
每个文件都有主次设备号。主设备号用来区分不同类型的设备,同一类型的设备具有相同的驱动程序,主设备号用来标识驱动程序。次设备号用来区分同一类型的不同设备,表示具体指向哪个设备。
对于普通文件来讲,其主设备号来标识储存该文件的实际存储设备的主设备号,而次设备号表示所在文件系统的所在分区(可以把同一存储设备的不同分区看成是不同的设备)。
二、stat.st_dev和st_rdev成员
1、文件的stat的数据成员st_dev记录了文件所在文件的主、次设备号信息。
st_dev是基本系统数据类型dev_t。Linux下的GNU C库把dev_t定义在头文件<sys/types.h>中,是一个64位无符号整数。
st_dev虽然是一个数据成员,但却包含了主、次设备号两个信息。不同的操作系统下,st_dev的实际位数以及主次设备号在st_dev中占用的位数可能不同。例如FreeBSD 5.2.1用8位表示主设备号,24位表示次设备号。Linux下的st_dev是64位,实际主次设备又分别只用了8位。这就给编写可移植性的程序带来了麻烦。
为了解决不同系统下st_dev的差异,大多库都提供了major和ninor宏来从st_dev中提取出主次设备号。然而不同系统下这两个宏定义的位置又有差别。Linux将这两个宏定义在<sys/sysmacros.h>中,而该头文件有包括在<sys/types.h>中;Solaris定义在<sys/mkdev.h>中,BSD定义在<sys/types>中。
GNU C库对major和ninor宏的定义原文如下:
__extension__
extern unsigned int gnu_dev_major (unsigned long long int __dev)
__THROW;
__extension__
extern unsigned int gnu_dev_minor (unsigned long long int __dev)
__THROW;
__extension__
extern unsigned long long int gnu_dev_makedev (unsigned int __major,
unsigned int __minor)
__THROW;
# if defined __GNUC__ && __GNUC__ >= 2 && defined __USE_EXTERN_INLINES
__extension__ __extern_inline unsigned int
__NTH (gnu_dev_major (unsigned long long int __dev))
{
return ((__dev >> 8) & 0xfff) | ((unsigned int) (__dev >> 32) & ~0xfff);
}
__extension__ __extern_inline unsigned int
__NTH (gnu_dev_minor (unsigned long long int __dev))
{
return (__dev & 0xff) | ((unsigned int) (__dev >> 12) & ~0xff);
}
__extension__ __extern_inline unsigned long long int
__NTH (gnu_dev_makedev (unsigned int __major, unsigned int __minor))
{
return ((__minor & 0xff) | ((__major & 0xfff) << 8)
| (((unsigned long long int) (__minor & ~0xff)) << 12)
| (((unsigned long long int) (__major & ~0xfff)) << 32));
}
# endif
/* Access the functions with their traditional names. */
# define major(dev) gnu_dev_major (dev)
# define minor(dev) gnu_dev_minor (dev)
# define makedev(maj, min) gnu_dev_makedev (maj, min)
#endif
从上面定义原文来看,好像是两个函数而不是两个宏。
2、只有字符特殊设备和块特殊设备才会有st_rdev值。此值包含实际设备的设备号。
实例 x.4.23.1.c
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
struct stat buf;
for (i = 1; i < argc; i++) {
printf("%s: ", argv[i]);
if (stat(argv[i], &buf) == -1) {
printf("stat error for %s\n", argv[i]);
continue;
}
printf("dev = %d/%d", major(buf.st_dev), minor(buf.st_dev));
if (S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode)) {
printf(" (%s) rdev = %d/%d",
(S_ISCHR(buf.st_mode)) ? "character" : "block",
major(buf.st_rdev), minor(buf.st_rdev));
}
printf("\n");
}
return 0;
}
编译与执行:
[root@localhost unixc]# echo "123" > /tmp/myfile
[root@localhost unixc]# cc x.4.23.1.c
[root@localhost unixc]# ./a.out /tmp/myfile /dev/sda /dev/sda1 /dev/tty0
/tmp/myfile: dev = 8/18
/dev/sda: dev = 0/5 (block) rdev = 8/0
/dev/sda1: dev = 0/5 (block) rdev = 8/1
/dev/tty0: dev = 0/5 (character) rdev = 4/0
[root@localhost unixc]#