4.23 st_dev和st_rdev成员-文件设备号

本文深入探讨Linux文件系统中主次设备号的概念,详细解释了它们的作用,并通过实例展示了如何使用stat.st_dev和st_rdev成员获取和解析这些设备号。文章还介绍了GNU库中的major和minor宏,以及它们在不同系统下的定义差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、主、次设备号

每个文件都有主次设备号。主设备号用来区分不同类型的设备,同一类型的设备具有相同的驱动程序,主设备号用来标识驱动程序。次设备号用来区分同一类型的不同设备,表示具体指向哪个设备。

对于普通文件来讲,其主设备号来标识储存该文件的实际存储设备的主设备号,而次设备号表示所在文件系统的所在分区(可以把同一存储设备的不同分区看成是不同的设备)。

二、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]#

[debug_ramdisk] c_ino = 300000 c_uid = 0 c_gid = 0 c_nlink = 1 c_mtime = 0 c_dev_maj = 0 c_dev_min = 0 c_rdev_maj = 0 c_rdev_min = 0 file_type = 16384 file_mode = "0o755" [dev] c_ino = 300001 c_uid = 0 c_gid = 0 c_nlink = 1 c_mtime = 0 c_dev_maj = 0 c_dev_min = 0 c_rdev_maj = 0 c_rdev_min = 0 file_type = 16384 file_mode = "0o755" [init] c_ino = 300002 c_uid = 0 c_gid = 0 c_nlink = 1 c_mtime = 0 c_dev_maj = 0 c_dev_min = 0 c_rdev_maj = 0 c_rdev_min = 0 file_type = 32768 file_mode = "0o750" [metadata] c_ino = 300003 c_uid = 0 c_gid = 0 c_nlink = 1 c_mtime = 0 c_dev_maj = 0 c_dev_min = 0 c_rdev_maj = 0 c_rdev_min = 0 file_type = 16384 file_mode = "0o755" [mnt] c_ino = 300004 c_uid = 0 c_gid = 0 c_nlink = 1 c_mtime = 0 c_dev_maj = 0 c_dev_min = 0 c_rdev_maj = 0 c_rdev_min = 0 file_type = 16384 file_mode = "0o755" [proc] c_ino = 300005 c_uid = 0 c_gid = 0 c_nlink = 1 c_mtime = 0 c_dev_maj = 0 c_dev_min = 0 c_rdev_maj = 0 c_rdev_min = 0 file_type = 16384 file_mode = "0o755" [second_stage_resources] c_ino = 300006 c_uid = 0 c_gid = 0 c_nlink = 1 c_mtime = 0 c_dev_maj = 0 c_dev_min = 0 c_rdev_maj = 0 c_rdev_min = 0 file_type = 16384 file_mode = "0o755" [sys] c_ino = 300007 c_uid = 0 c_gid = 0 c_nlink = 1 c_mtime = 0 c_dev_maj = 0 c_dev_min = 0 c_rdev_maj = 0 c_rdev_min = 0 file_type = 16384 file_mode = "0o755" [system] c_ino = 300008 c_uid = 0 c_gid = 0 c_nlink = 1 c_mtime = 0 c_dev_maj = 0 c_dev_min = 0 c_rdev_maj = 0 c_rdev_min = 0 file_type = 16384 file_mode = "0o755" ["system/bin"] c_ino = 300009 c_uid = 0 c_gid = 0 c_nlink = 1 c_mtime = 0 c_dev_maj = 0 c_dev_min = 0 c_rdev_maj = 0 c_rdev_min = 0 file_type = 16384 file_mode = "0o751" ["system/bin/e2fsck"] c_ino = 300010 c_uid = 0 c_gid = 0 c_nlink = 1 c_mtime = 0 c_dev_maj = 0 c_dev_min = 0 c_rdev_maj = 0 c_rdev_min = 0 file_type = 32768 file_mode = "0o755" ["system/etc"] c_ino = 300011 c_uid = 0 c_gid = 0 c_nlink = 1 c_mtime = 0 c_dev_maj = 0 c_dev_min = 0 c_rdev_maj = 0 c_rdev_min = 0 file_type = 16384 file_mode = "0o755" ["system/etc/ramdisk"] c_ino = 300012 c_uid = 0 c_gid = 0 c_nlink = 1 c_mtime = 0 c_dev_maj = 0 c_dev_min = 0 c_rdev_maj = 0 c_rdev_min = 0 file_type = 16384 file_mode = "0o755" ["system/etc/ramdisk/build.prop"] c_ino = 300013 c_uid = 0 c_gid = 0 c_nlink = 1 c_mtime = 0 c_dev_maj = 0 c_dev_min = 0 c_rdev_maj = 0 c_rdev_min = 0 file_type = 32768 file_mode = "0o644" ["TRAILER!!!"] c_ino = 300014 c_uid = 0 c_gid = 0 c_nlink = 1 c_mtime = 0 c_dev_maj = 0 c_dev_min = 0 c_rdev_maj = 0 c_rdev_min = 0 c_mode = 493 这些表是用来做什么的
最新发布
07-26
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值