zoukankan      html  css  js  c++  java
  • 设备特殊文件

    设备特殊文件

    引言

        st_dev和st_rdev这两个字段经常引起混淆
    1. struct stat
    2. {
    3. mode_t st_mode;/* file type & mode (permissions) */
    4. ino_t st_ino;/* i-node number (serial number) */
    5. dev_t st_dev;/* device number (file system) */
    6. dev_t st_rdev;/* device number for special files */
    7. nlink_t st_nlink;/* number of links */
    8. uid_t st_uid;/* user ID of owner */
    9. gid_t st_gid;/* group ID of owner */
    10. off_t st_size;/* size in bytes, for regular files */
    11. struct timespec st_atim;/* time of last access */
    12. struct timespec st_mtim;/* time of last modification */
    13. struct timespec st_ctim;/* time of last file status change */
    14. blksize_t st_blksize;/* best I/O block size */
    15. blkcnt_t st_blocks;/* number of disk blocks allocated */
    16. };
        每个文件系统所在的存储设备都由主、次设备号表示
        设备号所用的数据类型是基本系统数据类型dev_t。在<sys/stat.h>中声明如下:
    1. typedef__dev_tdev_t;
        主设备号标识设备驱动程序
        次设备号标识特定的子设备
        系统中与每个文件名关联的st_dev值是文件系统的设备名,该文件系统包含了这一文件名以及对应的i节点
        只有字符特殊文件和块特殊文件才有st_rdev值。此值包含实际设备的设备号

    major和minor宏

        我们通常使用两个宏:major和minor来访问主、次设备号,这也意味着我们无需关心这两个数是如何存放在dev_t对象中
        在<sys/sysmacros.h>定义了这两个宏, 而这个头文件又包含在<sys/type.h>中
    1. #define major(dev) gnu_dev_major (dev)
    实例
    1. /**
    2. * 为每个命令行参数打印设备号,另外,若此参数引用的是字符特殊文件或者块特殊文件,
    3. * 则还打印特殊文件的st_rdev值
    4. */
    5. #include<stdio.h>
    6. #include<stdlib.h>
    7. #include<sys/types.h>
    8. #include<sys/stat.h>
    9. #include<unistd.h>
    10. int main(int argc,char*argv[])
    11. {
    12. struct stat buf;
    13. int i =0;
    14. for(i =1; i < argc; i++)
    15. {
    16. printf("%s: ", argv[i]);
    17. if(stat(argv[i],&buf)<0)
    18. {
    19. err_ret("stat error");
    20. continue;
    21. }
    22. printf("dev = %d/%d ", major(buf.st_dev), minor(buf.st_dev));
    23. if(S_ISCHR(buf.st_mode))
    24. {
    25. printf("(character) rdev = %d/%d", major(buf.st_rdev), minor(buf.st_rdev));
    26. }
    27. elseif(S_ISBLK(buf.st_mode))
    28. {
    29. printf("(block) rdev = %d/%d", major(buf.st_rdev), minor(buf.st_rdev));
    30. }
    31. printf(" ");
    32. }
    33. exit(0);
    34. }
        程序运行如下:
    $ ./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. 磁盘盘组成示意图
        整颗磁盘的第一个扇区非常重要,因为它主要记录两个重要信息:
    1. 主要启动记录项(Master Boot Record, MBR):可以安装开机管理程序的地方,有446bytes
    2. 分区表(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)

    参考

    硬盘接口有几种?怎么看硬盘接口类型    http://www.pc841.com/article/20140903-34510.html
    鸟哥的Linux私房菜基础学习篇(第三版)  
     
  • 相关阅读:
    聚合查询2.0
    分词器2.0
    搜索和查询2.0
    Mapping2.0
    索引的CRUD2.0
    微信小程序:一则iOS下用video播放mp4文件问题排查
    flutter——android报错Manifest merger failed : Attribute application@allowBackup value=(false)
    HTML-meta
    HTML-实体
    html-vscode-liveServer
  • 原文地址:https://www.cnblogs.com/fireway/p/6103261.html
Copyright © 2011-2022 走看看