Linux下简单的mount命令实现(自动识别文件系统类型)

来源:互联网 发布:知乎 english in use 编辑:程序博客网 时间:2024/06/05 22:38

背景简述

mount()/umount()为Linux下挂载和卸载磁盘分区的系统调用,函数原型分别如下:

int mount(const char *source, const char *target,   const char *filesystemtype, unsigned long mountflags, const void *data);int umount(const char *target);

mount()的filesystemtype这个参数需要填入需要挂载的磁盘分区的文件系统类型,比如需要挂载fat32,那么这个参数需要填写为“vfat”,分区文件系统类型为ext2,需要填写为“ext2”;如果挂载成功,返回0,挂载失败,返回-1;

所以,这就需要我们获取当前要挂载的磁盘分区的文件系统类型;在shell上我们可以通过fdisk /dev/sda 这样类似的命令,然后敲p打印出现当前的磁盘分区信息,但是如果想直接通过函数调用的方式获取(非system()系统调用),还得另外找办法;

hexdump读取分区信息

我们利用hexdump这个工具,分别读取ext2/fat32/ntfs分区的信息,如下方法:

hexdump读fat32分区:

# hexdump -C -n 256 sda100000000  eb fe 90 4d 53 44 4f 53  35 2e 30 00 02 10 20 00  |...MSDOS5.0... .|00000010  02 00 00 00 00 f8 00 00  3f 00 ff 00 00 00 00 00  |........?.......|00000020  e0 d7 d2 01 54 3a 00 00  00 00 00 00 02 00 00 00  |....T:..........|00000030  01 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|00000040  00 01 29 76 6d 01 00 4e  4f 20 4e 41 4d 45 20 20  |..)vm..NO NAME  |00000050  20 20 46 41 54 33 32 20  20 20 00 00 00 00 00 00  |  FAT32   ......|00000060  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

有看到0x52 Offset开始的位置有字符串“FAT32”;

hexdump读ntfs分区:

# hexdump -C -n 256 /dev/sda200000000  eb 52 90 4e 54 46 53 20  20 20 20 00 02 08 00 00  |.R.NTFS    .....|00000010  00 00 00 00 00 f8 00 00  3f 00 ff 00 20 00 00 00  |........?... ...|00000020  00 00 00 00 80 00 00 00  df 3f 19 01 00 00 00 00  |.........?......|00000030  00 00 0c 00 00 00 00 00  02 00 00 00 00 00 00 00  |................|00000040  f6 00 00 00 01 00 00 00  6d 8e f9 6c b3 f9 6c 96  |........m..l..l.|00000050  00 00 00 00 fa 33 c0 8e  d0 bc 00 7c fb 68 c0 07  |.....3.....|.h..|00000060  1f 1e 68 66 00 cb 88 16  0e 00 66 81 3e 03 00 4e  |..hf......f.>..N|00000070  54 46 53 75 15 b4 41 bb  aa 55 cd 13 72 0c 81 fb  |TFSu..A..U..r...|00000080  55 aa 75 06 f7 c1 01 00  75 03 e9 dd 00 1e 83 ec  |U.u.....u.......|00000090  18 68 1a 00 b4 48 8a 16  0e 00 8b f4 16 1f cd 13  |.h...H..........|000000a0  9f 83 c4 18 9e 58 1f 72  e1 3b 06 0b 00 75 db a3  |.....X.r.;...u..|000000b0  0f 00 c1 2e 0f 00 04 1e  5a 33 db b9 00 20 2b c8  |........Z3... +.|000000c0  66 ff 06 11 00 03 16 0f  00 8e c2 ff 06 16 00 e8  |f...............|000000d0  4b 00 2b c8 77 ef b8 00  bb cd 1a 66 23 c0 75 2d  |K.+.w......f#.u-|000000e0  66 81 fb 54 43 50 41 75  24 81 f9 02 01 72 1e 16  |f..TCPAu$....r..|000000f0  68 07 bb 16 68 70 0e 16  68 09 00 66 53 66 53 66  |h...hp..h..fSfSf|

在Offset ox3处有发现“NTFS”这样的字符串;

ext2/ext3格式不太一样,直接读前面256bytes读不到有特别能说明文件系统类型的字符串。有参考Linux 文件系统的 Superblock, Inode, Dentry 和 File这篇blog,这篇blog里面有详细描述Linux下ext2的Inode和Block,其中有superblock的说明,结构体类型如下:

struct ext3_super_block {/*00*/ __u32 s_inodes_count;      /* inodes 计数 */__u32 s_blocks_count;      /* blocks 计数 */__u32 s_r_blocks_count;    /* 保留的 blocks 计数 */__u32 s_free_blocks_count; /* 空闲的 blocks 计数 *//*10*/ __u32 s_free_inodes_count; /* 空闲的 inodes 计数 */__u32 s_first_data_block;  /* 第一个数据 block */__u32 s_log_block_size;    /* block 的大小 */__s32 s_log_frag_size;     /* 可以忽略 *//*20*/ __u32 s_blocks_per_group;  /* 每 block group 的 block 数量 */__u32 s_frags_per_group;   /* 可以忽略 */__u32 s_inodes_per_group;  /* 每 block group 的 inode 数量 */__u32 s_mtime;             /* Mount time *//*30*/ __u32 s_wtime;             /* Write time */__u16 s_mnt_count;         /* Mount count */__s16 s_max_mnt_count;     /* Maximal mount count */__u16 s_magic;             /* Magic 签名 */__u16 s_state;             /* File system state */__u16 s_errors;            /* Behaviour when detecting errors */__u16 s_minor_rev_level;   /* minor revision level *//*40*/ __u32 s_lastcheck;         /* time of last check */__u32 s_checkinterval;     /* max. time between checks */__u32 s_creator_os;        /* 可以忽略 */__u32 s_rev_level;         /* Revision level *//*50*/ __u16 s_def_resuid;        /* Default uid for reserved blocks */__u16 s_def_resgid;        /* Default gid for reserved blocks */__u32 s_first_ino;         /* First non-reserved inode */__u16 s_inode_size;        /* size of inode structure */__u16 s_block_group_nr;    /* block group # of this superblock */__u32 s_feature_compat;    /* compatible feature set *//*60*/ __u32 s_feature_incompat;  /* incompatible feature set */__u32 s_feature_ro_compat; /* readonly-compatible feature set *//*68*/ __u8  s_uuid[16];          /* 128-bit uuid for volume *//*78*/ char  s_volume_name[16];   /* volume name *//*88*/ char  s_last_mounted[64];  /* directory where last mounted *//*C8*/ __u32 s_algorithm_usage_bitmap; /* 可以忽略 */__u8  s_prealloc_blocks;        /* 可以忽略 */__u8  s_prealloc_dir_blocks;    /* 可以忽略 */__u16 s_padding1;               /* 可以忽略 *//*D0*/ __u8  s_journal_uuid[16]; /* uuid of journal superblock *//*E0*/ __u32 s_journal_inum;     /* 日志文件的 inode 号数 */__u32 s_journal_dev;      /* 日志文件的设备号 */__u32 s_last_orphan;      /* start of list of inodes to delete *//*EC*/ __u32 s_reserved[197];    /* 可以忽略 */};

其中s_magic在ext2/ext3上固定为0xEF53。这个superblock放在分区的superblock1上(一个superblock大小为0x400bytes),所以可以通过s_magic去判定是否是ext2或者ext3,通过hexdump打印ext2的superblock1如下:

# hexdump -C -n 1024 -s 1024 sda300000400  40 ce 08 00 fc 27 23 00  ff c1 01 00 71 9a 22 00  |@....'#.....q.".|00000410  33 ce 08 00 00 00 00 00  02 00 00 00 02 00 00 00  |3...............|00000420  00 80 00 00 00 80 00 00  c0 1f 00 00 78 40 ca 59  |............x@.Y|00000430  5d 00 00 00 05 00 25 00  53 ef 00 00 01 00 00 00  |].....%.S.......|00000440  06 04 00 00 00 4e ed 00  00 00 00 00 01 00 00 00  |.....N..........|00000450  00 00 00 00 0b 00 00 00  00 01 00 00 20 00 00 00  |............ ...|00000460  02 00 00 00 01 00 00 00  14 1f 7f da 41 8f 46 fb  |............A.F.|00000470  81 ef 72 2e 2f fa db 25  00 00 00 00 00 00 00 00  |..r./..%........|00000480  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|*000004e0  00 00 00 00 00 00 00 00  00 00 00 00 9d f7 68 b5  |..............h.|000004f0  f1 14 44 86 93 ca 80 84  aa 93 05 41 01 00 00 00  |..D........A....|00000500  00 00 00 00 00 00 00 00  06 04 00 00 00 00 00 00  |................|00000510  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|*00000550  00 00 00 00 00 00 00 00  00 00 00 00 1c 00 1c 00  |................|00000560  02 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|00000570  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

C实现获取文件系统类型

根据上面的实验结果,所实现的获取分区文件系统函数如下:

typedef enum{    FS_NTFS,    FS_FAT32,    FS_EXT2,    FS_ERROR_TYPE,}FILE_SYS_TYPE;/** * [_getFSType get the filesystem type of partion] * @param  devFD [the handle of usb partition device from open()] * @return       [the filesystem type] */static FILE_SYS_TYPE _getFSType(int devFD){    unsigned char tmpBuffer[0x400];    unsigned char* pOffset = NULL;    unsigned int readSize = 0;    pOffset = &tmpBuffer[0];    memset(pOffset, 0x00, 0x400);    //read the tag data for ntfs/fat32    readSize = read(devFD, pOffset, 0x100);    if(!readSize)    {        printf("read device file failed!\n");        return FS_ERROR_TYPE;    }    if(!memcmp((const void*)(pOffset+0x52), (const void*)"FAT32", 5))//th offset with 0x52 is fat32 tag;    {        printf("filesystem:fat32!\n");        return FS_FAT32;    }    else if(!memcmp((const void*)(pOffset+0x3), (const void*)"NTFS", 4))//the offset with 0x3 is ntfs tag;    {        printf("filesystem:ntfs!\n");        return FS_NTFS;    }    else    {        memset(pOffset, 0x00, 0x400);        lseek(devFD,0x400, SEEK_SET); //seek to superblock1;        readSize = read(devFD, pOffset, 0x400);//read the superblock1 to buffer;        if(!readSize)        {            printf("read1 device file failed!\n");            return FS_ERROR_TYPE;        }        pOffset = pOffset+0x38; //the offset 0x438 is the tag of ext2:0x53 0xef;        if((pOffset[0] == 0x53) && (pOffset[1] == 0xef))        {            printf("filesystem:ext2 or ext3!\n");            return FS_EXT2;        }        else        {            printf("the offset 0x438 vaule is:0x%x 0x%x!\n", pOffset[0], pOffset[1]);        }    }    printf("Unknown filesystem type!\n");    return FS_ERROR_TYPE;}

上面的函数要求传入分区对应的handle(用open()函数得到),然后返回文件系统类型;

测试函数

测试函数代码auto_mount.c如下:

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/stat.h>#include <fcntl.h>/** * [main auto mount usb partions] * @param  argc [the arguments number] * @param  argv [the arguments pointer] * @return      [the error code] */int main(int argc, char *argv[]){    char devPath[512];    char mountPath[512];    int devFD = 0;    int ret = -1;    FILE_SYS_TYPE fsType = FS_ERROR_TYPE;    if(argc != 3)    {        printf("error paramter!\n");        return -1;    }    snprintf(devPath,511,"%s", argv[1]);    snprintf(mountPath,511,"%s", argv[2]);    printf("devPath:%s, mountPath:%s\n", devPath, mountPath);    devFD = open(devPath, O_RDONLY);    if(!devFD)    {        printf("Open device failed!\n");        return -1;    }    fsType = _getFSType(devFD);    printf("fs type:%d\n", fsType);    switch(fsType)    {        case FS_EXT2:            ret=mount((const char*)devPath, (const char*)mountPath, (const char*)"ext2", 0, NULL);            break;        case FS_NTFS:            ret=mount((const char*)devPath, (const char*)mountPath, (const char*)"ntfs3g", 0, NULL);            break;        case FS_FAT32:            ret=mount((const char*)devPath, (const char*)mountPath, (const char*)"vfat", 0, NULL);            break;        default:            printf("Unknown filesystem type!\n");    }    printf("mount result:%d\n", ret);    close(devFD);    return 0;}

测试函数可以如下方法编译:
gcc auto_mount.c -o auto_mount;

在sudo chmod +x auto_mount增加可执行权限后,可以如下方法运行:

./auto_mount /dev/sda1 /mnt/sda1; //将/dev/sda1这个设备mount到/mnt/sda1这个目录;
阅读全文
1 0