首页 > 代码库 > 设备特殊文件
设备特殊文件
设备特殊文件
引言
st_dev和st_rdev这两个字段经常引起混淆
struct stat
{
mode_t st_mode; /* file type & mode (permissions) */
ino_t st_ino; /* i-node number (serial number) */
dev_t st_dev; /* device number (file system) */
dev_t st_rdev; /* device number for special files */
nlink_t st_nlink; /* number of links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
off_t st_size; /* size in bytes, for regular files */
struct timespec st_atim; /* time of last access */
struct timespec st_mtim; /* time of last modification */
struct timespec st_ctim; /* time of last file status change */
blksize_t st_blksize; /* best I/O block size */
blkcnt_t st_blocks; /* number of disk blocks allocated */
};
每个文件系统所在的存储设备都由主、次设备号表示
设备号所用的数据类型是基本系统数据类型dev_t。在<sys/stat.h>中声明如下:
typedef __dev_t dev_t;
主设备号标识设备驱动程序
次设备号标识特定的子设备
系统中与每个文件名关联的st_dev值是文件系统的设备名,该文件系统包含了这一文件名以及对应的i节点
只有字符特殊文件和块特殊文件才有st_rdev值。此值包含实际设备的设备号
major和minor宏
我们通常使用两个宏:major和minor来访问主、次设备号,这也意味着我们无需关心这两个数是如何存放在dev_t对象中
在<sys/sysmacros.h>定义了这两个宏, 而这个头文件又包含在<sys/type.h>中
#define major(dev) gnu_dev_major (dev)
实例
/**
* 为每个命令行参数打印设备号,另外,若此参数引用的是字符特殊文件或者块特殊文件,
* 则还打印特殊文件的st_rdev值
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
struct stat buf;
int i = 0;
for (i = 1; i < argc; i++)
{
printf("%s: ", argv[i]);
if (stat(argv[i], &buf) < 0)
{
err_ret("stat error");
continue;
}
printf("dev = %d/%d ", major(buf.st_dev), minor(buf.st_dev));
if (S_ISCHR(buf.st_mode))
{
printf("(character) rdev = %d/%d", major(buf.st_rdev), minor(buf.st_rdev));
}
else if (S_ISBLK(buf.st_mode))
{
printf("(block) rdev = %d/%d", major(buf.st_rdev), minor(buf.st_rdev));
}
printf("\n");
}
exit(0);
}
程序运行如下:
$ ./a.out / /home/fireway/ /dev/tty[01]
/: dev = 8/1
/home/fireway/: dev = 8/1
/dev/tty0: dev = 0/6 (character) rdev = 4/0
/dev/tty1: dev = 0/6 (character) rdev = 4/1
$ mount <---------------------哪些目录安装在哪些设备上(详细原理见下文)
/dev/sda1 on / type ext4 (rw,errors=remount-ro)
proc on /proc type proc (rw,noexec,nosuid,nodev)
sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)
none on /sys/fs/cgroup type tmpfs (rw)
none on /sys/fs/fuse/connections type fusectl (rw)
none on /sys/kernel/debug type debugfs (rw)
none on /sys/kernel/security type securityfs (rw)
udev on /dev type devtmpfs (rw,mode=0755)
devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620)
tmpfs on /run type tmpfs (rw,noexec,nosuid,size=10%,mode=0755)
none on /run/lock type tmpfs (rw,noexec,nosuid,nodev,size=5242880)
none on /run/shm type tmpfs (rw,nosuid,nodev)
none on /run/user type tmpfs (rw,noexec,nosuid,nodev,size=104857600,mode=0755)
none on /sys/fs/pstore type pstore (rw)
systemd on /sys/fs/cgroup/systemd type cgroup (rw,noexec,nosuid,nodev,none,name=systemd)
gvfsd-fuse on /run/user/112/gvfs type fuse.gvfsd-fuse (rw,nosuid,nodev,user=lightdm)
$ ls -l /dev/tty[01] /dev/sda[01]
brw-rw---- 1 root disk 8, 1 11月 17 07:52 /dev/sda1
crw--w---- 1 root tty 4, 0 11月 17 07:52 /dev/tty0
crw-rw---- 1 root tty 4, 1 11月 17 07:52 /dev/tty1
我们给程序传了4个参数,前两个参数是目录(/和/home/fireway), 后两个参数是设备名/dev/tty[01]。
认识设备特殊文件
在linux系统,每个设备都会被当成一个文件对待。比如IDE接口的硬盘(IDE的英文全称为“Integrated Drive Electronics”,即“电子集成驱动器”)的文件名即为/dev/hd[a-d]。
通常来说,电脑硬盘主要有IDE以及SATA两种接口类型,其中以前的旧电脑一般都是IDE硬盘接口,该接口由于传输速度慢,如今早已被淘汰,现在的新电脑都是SATA硬盘接口。
目前硬盘接口均采用SATA接口,SATA接口有分为SATA2.0以及SATA3.0,其中SATA2.0最大传输速度为300M/s,而SATA3.0最大传输速率为600M/s。如今固态硬盘均采用的是SATA3.0接口,而普通的机械硬盘很多也开始全面采用SATA3.0接口,只要部分容量较小,价格比较低的机械硬盘还是用的SATA2.0接口。
下面列出几个常见的设备与其在 Linux 当中的文件名:
设备 | 在Linux内的文件名 |
IDE硬盘 | /dev/hd[a-d] |
SCSI / SATA / USB 硬盘 | /dev/sd[a-p] |
U盘,全称USB闪存盘,英文名“USB flash disk” | /dev/sd[a-p](与SATA 相同) |
软盘驱动器 | /dev/fd[0-1] |
打印机 | 25 针: /dev/lp[0-2] USB: /dev/usb/lp[0-15] |
鼠标 | USB: /dev/usb/mouse[0-15] PS2: /dev/psaux |
当前CDROM/DVDROM | /dev/cdrom |
当前的鼠标 | /dev/mouse |
磁带机 | IDE: /dev/ht0
SCSI: /dev/st0 |
磁盘和磁盘分区
一块磁盘是可以被分割成多个分区(partition),比如Windows就把一个磁盘划分成C、D、E盘,这个就是分区(partition),但是Linux的设备都是以文件形式存在,那它的分区以是什么表示的呢?
磁盘盘上面又可细分成扇区(Sector)与柱面(Cylinder), 其中扇区每个为 512bytes 。假设磁盘只有一个磁盘盘,如下图1所示:
图1. 磁盘盘组成示意图
整颗磁盘的第一个扇区非常重要,因为它主要记录两个重要信息:
- 主要启动记录项(Master Boot Record, MBR):可以安装开机管理程序的地方,有446bytes
- 分区表(partition table):记录整颗硬盘分区的状态,有64bytes
图2.分区表的作用示意图
上图2中我们假设硬盘只有400个柱面,共划分成4个分区,第四个分区在第301到400号柱面的范围。假设硬盘设备文件名为/dev/hda,那么这四个分区在Linux系统中的设备文件名如下:
P1:/dev/hda1
P2:/dev/hda2
P3:/dev/hda3
P4:/dev/hda4
根据上面图示和说明,我们可以简单总结如下:
- 其实所谓的“分区”,只是针对这个64bytes的分区表设定而已
- 硬盘默认的分区表仅能写入4个划分信息
- 这4组划分信息我们称为主要分区(Primary partition)或扩展分区(Extended partition)
- 分区的最小单位为柱面
- 当系统写入磁盘时,一定会参考分区表,才能针对某个分区进行数据处理
那么为什么要进行磁盘分区呢?
- 数据的安全性
- 系统的性能效率
既然分区表只能记录4组划分信息,那么是否代表一颗硬盘最多只能划分4个分区呢?当然不是,在Windows、Linux系统中,我们通过上面的扩展分区(extended partition)的方式,划分很多个分区。如下图所示:
图3. 磁盘分区表、扩展分区表的作用示意图
在图3中,默认的分区表仅用到两个,P1为为主要分区,P2为扩展分区,请注意,使用扩展分区的目的是使用额外的扇区来记录分区信息,扩展分区本身并不能拿来格式化,然后我们通过扩展分区所指向的这块区域继续做划分。
正如图3右下角的这块区域又被划分出5个分区,这5个分区是由扩展分区划分出来的,被称为逻辑分区(logical partition)。因此,这些分区在Linux系统的设备文件名如下:
P1:/dev/hda1
P2:/dev/hda2
L1:/dev/hda5
L2:/dev/hda6
L3:/dev/hda7
L4:/dev/hda8
L5:/dev/hda9
仔细一瞧,怎么设备文件名没有/dev/hda[34]呢?因为前面4个号码都是留给Primary或Extended,所以逻辑分区的设备名称号码就由5开始。
我们了解了Primary partition, Extended partition和Logical partition概念后,做一个简单的总结:
- 逻辑分区是由扩展分区划分出来的分区
- 主要分区最多可以有4个(硬盘限制)
- 扩展分区最多只有一个(操作系统的限制)
- 作为数据存取,能够被格式化的,是主要分区和逻辑分区,扩展分区无法格式化
- 逻辑分区的数量主要依赖操作系统,在Linux系统中,IDE硬盘最多有59个逻辑分区(5~63号),STAT硬盘则有11个逻辑分区(5~15号)
几乎只要读取硬盘都会从第一个扇区所记录的分区表和MBR获取到,因此如果整颗硬盘的第一个扇区坏掉,那这颗磁盘大概就没用了。因为系统如果找不到分区表,怎么知道如何读取柱面呢?
目录树结构
图4. 目录树相关性示意图
如上图,长方形为目录,波浪形为文件。Linux 与其他类 UNIX 系统一样并不区分文件与目录:目录是记录了其他文件名的文件。
/ 根目录
├── bin 存放用户二进制文件
├── boot 存放内核引导配置文件
├── dev 存放设备文件
├── etc 存放系统配置文件
├── home 用户主目录
├── lib 动态共享库
├── lost+found 文件系统恢复时的恢复文件
├── media 可卸载存储介质挂载点
├── mnt 文件系统临时挂载点
├── opt 附加的应用程序包
├── proc 系统内存的映射目录,提供内核与进程信息
├── root root 用户主目录
├── sbin 存放系统二进制文件
├── srv 存放服务相关数据
├── sys sys 虚拟文件系统挂载点
├── tmp 存放临时文件
├── usr 存放用户应用程序
└── var 存放邮件、系统日志等变化文件
我们现在知道整个Linux系统使用的是目录树结构,但是我们的文件其实是放置在磁盘分区的,现在的问题是“如何结合目录树与磁盘内的数据”,这个就需要牵扯到mount(挂载)的概念。
所谓的“挂载”,是指将一个设备(通常是存储设备)挂接到一个已存在的目录上。 我们要访问存储设备中的文件,必须将文件所在的分区挂载到一个已存在的目录上, 然后通过访问这个目录来访问存储设备。如下图,假设硬盘分为两个分区,partition1是挂载到跟目录,partition2是挂载到/home目录,也就是说,当数据放置在/home内的各个目录时,数据是放置在partition2,如果不是放在/home目录的文件,那么数据就会被放置在partition1上。
图5. 目录树与分区之前的相关性
文件系统与格式化
磁盘分区完毕后,还需要格式化(format),为什么呢?这是因为每种操作系统所设定的文件属性/权限并不相同,为了存放这些文件所需的数据,需要将分区进行格式化,以便称为操作系统能够利用的文件系统格式(filesystem)。
每种操作系统所使用的文件系统并不相同,
操作系统 | 文件系统 |
windows 98以前 | FAT(或FAT16) |
windows 2000 | NTFS |
Linux | Ex2(Linux second extended file system, ext2fs) |
参考
IDE http://baike.baidu.com/subview/5775/5401664.htm#viewPageContent
硬盘接口有几种?怎么看硬盘接口类型 http://www.pc841.com/article/20140903-34510.html
鸟哥的Linux私房菜基础学习篇(第三版)
设备特殊文件
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。