美文网首页
Android Vold 随笔之e2fsprogs blkid

Android Vold 随笔之e2fsprogs blkid

作者: Nothing_655f | 来源:发表于2020-12-17 16:10 被阅读0次

    Android Vold 随笔之e2fsprogs blkid

    blkid 命令对查询设备上所采用文件系统类型进行查询。blkid主要用来对系统的块设备(包括交换分区)所使用的文件系统类型、LABEL、UUID等信息进行查询。

    背景

    Android 7.1 遇到一个sd 64G exfat不显示盘符的问题

    调试过程

        VolumeManager.cpp
             VolumeManager::VolumeManager() {
            -    mDebug = false;
            +    mDebug = true;
                 mActiveContainers = new AsecIdCollection();
                 mBroadcaster = NULL;
                 mUmsSharingCount = 0;
            @@ -259,6 +259,9 @@ char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
             }
    
             int VolumeManager::setDebug(bool enable) {
            +
            +       enable = true;
            +       SLOGD("%s %d enable:%d\n",__FUNCTION__, __LINE__, enable);
    
    

    出现问题时有如下错误

    01-01 08:00:23.037 3865 3911 E vold : Failed to pclose /system/bin/blkid -c /dev/null -s TYPE -s UUID -s LABEL /dev/block/vold/public:179,129 : No such file or directory
    
    

    NG时 使用blkid命令同样看不到设备,

    OK时 可以看到

    /dev/block/vold/public:179,129: UUID="5DB1-2645" LABEL="0000-0000" TYPE="exfat"
    
    

    使用busybox blkid可以看到对应设备

    :/ # busybox blkid
    /dev/block/vold/public:179,129: TYPE="exfat"*
    

    调用blkid 代码流程

        H:\code\system\vold\PublicVolume.cpp
            @@ -128,7 +129,7 @@ status_t PublicVolume::doMount() {
                     mFsType != "hfs" &&
                     mFsType != "iso9660" &&
                     mFsType != "udf") {
            -        LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;
            +        LOG(ERROR) << getId() << "PublicVolume unsupported filesystem " << mFsType;
    
                 status_t PublicVolume::readMetadata() {
                     status_t res = ReadMetadataUntrusted(mDevPath, mFsType, mFsUuid, mFsLabel);
                +       LOG(ERROR) << " DEBUG " << __FUNCTION__;
        H:\code\system\vold\Utils.cpp
            status_t ReadMetadataUntrusted(const std::string& path, std::string& fsType,
                    std::string& fsUuid, std::string& fsLabel) {
                return readMetadata(path, fsType, fsUuid, fsLabel, true);
            }
    
            static status_t readMetadata(const std::string& path, std::string& fsType,
                    std::string& fsUuid, std::string& fsLabel, bool untrusted)
    
                cmd.push_back(kBlkidPath); //Note: kBlkidPath = "/system/bin/blkid";
                cmd.push_back("-c");
                cmd.push_back("/dev/null");
                cmd.push_back("-s");
                cmd.push_back("TYPE");
                cmd.push_back("-s");
                cmd.push_back("UUID");
                cmd.push_back("-s");
                cmd.push_back("LABEL");
                cmd.push_back(path);
    
                std::vector<std::string> output;
                status_t res = ForkExecvp(cmd, output, untrusted ? sBlkidUntrustedContext : sBlkidContext);
    
    

    源码中修改为使用busybox , 如下也可以识别到

    code\system\vold\Utils.cpp

    readMetadata方法

    if (access("/system/xbin/blkid", F_OK)!=-1)
    { 
        cmd.push_back("/system/xbin/blkid"); 
        LOG(ERROR) << "busybox exist" << __FUNCTION__;
    } else{ 
        cmd.push_back(kBlkidPath); 
    }
    
    

    网上查了下也有类似的问题,是ext2 的 blkid 命令 不支持卷标

    Is it possible to find out volume label of SD card inserted into Android device?

    I understand that Android is designed to have just one "external storage" (as returned by Environment.getExternalStorageDirectory()), but there are quite a few devices in the wild that have internal flash as "external storage" and an SD card mounted under that or even wilder combinations (see this other question). It is possible to enumerate these additional devices by reading /proc/mounts, but we need something to identify them to the user. Is there any chance to get to their volume labels?

    I checked that Linux vfat driver ignores the volume label dentry altogether and that blkid from util-linux reads the vfat itself. I also checked that, at least on device I have, the block device of the SD card has mode 660 and owner root.root, so I can't do that. So basically it boils down to whether there is any utility that could read it available.

    解决方案

    I have found a solution.

    The easiest solution is to build busybox and use it like this: busybox blkid

    Complicated solution is to find blkid for Android and find what you need in its source code (blkid_dev_devname function).

    来自 http://www.it1352.com/119156.html

    blkid 其源码在这个路径
    external/e2fsprogs

    可执行文件在

    external/e2fsprogs$ ls -l misc/blkid.c

    其动态库在

    external/e2fsprogs$ ls -l lib/blkid/

    大概追踪了下流程,以敲 blkid ,不带参数为例的流程

    其输出如下:

    XXXX:/ # blkid                                
    add_vold_cache 48 
    add_vold_cache 52 
    add_vold_cache 48 
    add_vold_cache 52 
    blkid_dev_next 159 
    blkid_dev_next 175 name:/dev/block/zram0
    /dev/block/zram0: TYPE="swap" UUID="828638c1-4615-40ca-9293-3bb24e4aeb7f" 
    blkid_dev_next 159 
    blkid_dev_next 175 name:/dev/block/cache
    /dev/block/cache: UUID="57f8f4bc-abf4-655f-bf67-946fc0f9f25b" TYPE="ext4" 
    blkid_dev_next 159 
    blkid_dev_next 175 name:/dev/block/param
    /dev/block/param: UUID="57f8f4bc-abf4-655f-bf67-946fc0f9f25b" TYPE="ext4" 
    blkid_dev_next 159 
    blkid_dev_next 175 name:/dev/block/tee
    /dev/block/tee: UUID="57f8f4bc-abf4-655f-bf67-946fc0f9f25b" TYPE="ext4" 
    blkid_dev_next 159 
    blkid_dev_next 175 name:/dev/block/system
    /dev/block/system: LABEL="system" UUID="da594c53-9beb-f85c-85c5-cedf76546f7a" TYPE="ext4" 
    blkid_dev_next 159 
    blkid_dev_next 175 name:/dev/block/data
    /dev/block/data: UUID="57f8f4bc-abf4-655f-bf67-946fc0f9f25b" TYPE="ext4" 
    blkid_dev_next 159 
    blkid_dev_next 175 name:/dev/block/vold/public:179,129
    blkid_dev_next 159 
    blkid_dev_next 175 name:/dev/block/vold/disk:179,128
    blkid_dev_next 159 
    
    

    blkid 识别设备代码流程

    1. blkid_probe_all 识别已有的块设备分区
    2. 通过 get_vold_devices 遍历 /dev/block/vold 下的设备
    3. 如果其有设备的话 通过 add_vold_cache 加入到链表中
    4. 通过blkid_dev_next 遍历设备是否存在
    5. 如果设备存在通过blkid_verify 判断设备是否符合要求, // 我这个问题是这里error return了
    6. 如果blkid_verify返回正确则 通过print_tags 输出设备信息
    blkid_probe_all(cache);
    int cnt = get_vold_devices();
    fprintf(stderr, "%s %d vold's cnt:%d\n", __FUNCTION__, __LINE__, cnt);
    for (i = 0; i < cnt; i++) {
        fprintf(stderr, "%s %d vold's :%s\n", __FUNCTION__, __LINE__, device_names[i]);
        add_vold_cache(cache, device_names[i]);
    }
    fprintf(stderr, "%s %d \n", __FUNCTION__, __LINE__);
    
    iter = blkid_dev_iterate_begin(cache);
            fprintf(stderr, "%s %d \n", __FUNCTION__, __LINE__);
    blkid_dev_set_search(iter, search_type, search_value);
            fprintf(stderr, "%s %d \n", __FUNCTION__, __LINE__);
    while (blkid_dev_next(iter, &dev) == 0) {
        dev = blkid_verify(cache, dev);
        if (!dev) {
            fprintf(stderr, "%s %d blkid_verify fail\n", __FUNCTION__, __LINE__);
            continue;
        }
        print_tags(dev, show, numtag, output_format);
        err = 0;
    }
    fprintf(stderr, "%s %d \n", __FUNCTION__, __LINE__);
    blkid_dev_iterate_end(iter);
    
    

    问题解决办法

    方法一

    原先是打算使用busybox 来处理这个问题,这样子意味着要放弃原有的blkid 工具集,于是乎随手看了下e2fsprogs这里面的上code记录

    一看还是发现有问题,不能直接改为busybox,@-@

    因为平台有自己的客制化修改,贴下记录上code 记录,(commit信息抹去部分信息不便放出来)

    ~/code/external/e2fsprogs$ git log
    commit 1
        patch: display Chinese label properly
    
    commit 2
        blkid: support exfat
    
        blkid support exfat
    
    

    一看上面这个commit,马上将U盘改为中文名,然后使用busybox的case 下,重启一看,虽然是挂载上了,但是盘符果然如猜想的是乱码了

    扩展: 修改busybox 支持中文

    然后使用busybox ls 看中文文件也是乱码,此时 参照 ARM+LINUX嵌入式系统的终端显示中文乱码解决 这里修改了,一顿操作后

    补充我这边的修改,我这边看结合看源码中unicode.c 其实subset 这个case外面还有两个宏的判断需要开,

    函数如下

    if (CONFIG_LAST_SUPPORTED_WCHAR && wc > CONFIG_LAST_SUPPORTED_WCHAR)
    
        goto subst;
    
        w = wcwidth(wc);
    
        if ((ENABLE_UNICODE_COMBINING_WCHARS && w < 0) /* non-printable wchar */
    
         || (!ENABLE_UNICODE_COMBINING_WCHARS && w <= 0)
    
         || (!ENABLE_UNICODE_WIDE_WCHARS && w > 1)
    
        ) {
    
         subst:
    
        wc = CONFIG_SUBST_WCHAR;
    
        w = 1;
    
    }
    
    

    增加修改如下

    CONFIG_UNICODE_WIDE_WCHARS=y
    
    CONFIG_UNICODE_COMBINING_WCHARS=y
    
    

    出现问题时,所以要结合实际例子来看,冷静分析

    blkid 支持中文字符

    虽然busybox ls 也是能显示中文字符了,但是挂载的时候显示的盘符还是乱码..

    继续追踪,盘符使用的名称是 LABEL 标签, 结合原有的Vendor 厂商修改显示中文的方法,可以参考这一段,

    这是方法一

    5: blkid如何支持中文

    这个就涉及到字符集相关的问题了, 说一个迷惑了我很久的字符集问题。

    字符集包括unicode, gbk 以及gb2312等等, 但是utf-8, 这个东西不是字符集。这个是字符编码。

    举个例子就明白啥叫字符编码了。

    C中的字符串(char*)问题, 我们认为一个字符串的长度是, 读取到ASCII 0(‘/0’)的位置位置。

    假设字符串 "A" 的GBK和UTF8编码都是 0x410 x00, 为啥后面多了个0x00, 这个就是字符串的结束位置。

    字符A的 Unicode编码是 0x00 0x41, 如果用char*传递unicode字符串, 不知道字符串大小, 肯定是有问题的。 读到第一个0x00就结束了。

    还不明白可以百度了。

    对于vfat,fat32格式的U盘, 在windows下命名中文, 保存的字符编码是CP936(跟GBK差不多), 但是对于ntfs格式的u盘, 保存的方式是unicode。

    这里涉及到android(linux)的编码问题, linux的默认编码是utf-8. 所以如果要正常显示, 需要在linux中合适的位置坐转码。

    思路:

    (只涉及中文, 韩文日文不考虑)在blkid这里把, 把编码直接从gbk转到utf8. (/external/e2fsprogs/misc/blkid.c)

    特殊的ntfs获取卷标的地方, 为了上层的gbk编码兼容, 可以直接把unicode先转成gbk。(/external/e2fsprogs/lib/blkid/probe.c)

    至于编码之间的转换可以参考网上的代码, 也可以使用开源的库iconv. 个人认为可以代码量比较小, 可以考虑网上的参考代码。

    ————————————————

    版权声明:本文为CSDN博主「ouo555」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

    原文链接:https://blog.csdn.net/ouo555/article/details/38011505

    方法二

    方法二:如果不修改为busybox,看看为什么原来看e2fsporgs blkid无法识别到盘符,可以看到我的sd原来就是exFat格式,可以看到前面的 **Vendor commit 1 **这笔修改就是支持exFat格式的,看这笔commit的提交,发现其修改怎么有点似曾相识的感觉,再仔细对比下busybox的 probe方法,发现Vendor就是移植busybox的方法,那么只要追下flow大概就是知道哪里出的问题了。

    最后发现是Vendor 移植后的代码少了一个判断条件即没有判断是否有type类型,刚好这个sd卡只有type 类型,所以就直接函数返回错误了

    修改如下:

     @@ -1601,7 +1601,10 @@ int get_label_uuid(int fd, char **label, char **uuid, char **type)
    
       size = 0;
    
       if (volume_id_probe_all(vid, /*0,*/ size) != 0)
            goto ret;
    
    -    if (vid->label[0] != '\0' || vid->uuid[0] != '\0') {
    +    if (vid->label[0] != '\0' || vid->uuid[0] != '\0'
    +        //  Patch Start
    +        || vid->type[0] != '\0') {
    +        //  Patch End
    
    

    这个是busybox的源码

    /* Returns !0 on error.
     \* Otherwise, returns malloc'ed strings for label and uuid
     \* (and they can't be NULL, although they can be "").
     \* NB: closes fd.
     */
    
    static int
    get_label_uuid(int fd, char **label, char **uuid, const char **type)
    {
        if (vid->label[0] != '\0' || vid->uuid[0] != '\0'
        #if ENABLE_FEATURE_BLKID_TYPE
         || vid->type != NULL
        #endif
        ) {
            *label = xstrndup(vid->label, sizeof(vid->label));
            *uuid = xstrndup(vid->uuid, sizeof(vid->uuid));
            #if ENABLE_FEATURE_BLKID_TYPE
            *type = vid->type;
            dbg("found label '%s', uuid '%s', type '%s'", \*label, \*uuid, \*type);
            #else
            dbg("found label '%s', uuid '%s'", *label, *uuid);
            #endif
            rv = 0;
        }
    
        // …
    
    }
    
    

    方法三

    方法三,既然exFat的方法是Vendor 自己添加的,那么可以看看最新的e2fsprogs是否可以支持到对应exFat格式和Unicode 显示

    这里即贴下结论了,最新的e2fsprogs代码可以支持exFat,验证过程不描述了,亲测可行,代码下载如下

    This is the home page for the e2fsprogs package. It provides the filesystem utilities for use with the ext2 filesystem. It also supports the ext3 and ext4 filesystems.

    The e2fsprogs Sourceforge summary page can be found here. For more information about the ext2 filesystem, click here.

    The latest development sources for e2fsprogs is maintained in a Git repository at git://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git. A quick tutorial about how to start using git can be found here.

    来自 http://e2fsprogs.sourceforge.net/

    或者上GitHub 下载 https://github.com/tytso/e2fsprogs

    Ssh 链接 git@github.com:tytso/e2fsprogs.git

    合这几笔commit 就可以了

        commit a850bc56e0aa7370b7e0e81d8dbab93841829f98
        Author: liminghao <liminghao@xiaomi.com>
        Date:   Wed Mar 1 17:54:42 2017 +0800
    
            AOSP: blkid: add support to recognize exfat to blkid.
    
            we can now identify exfat filesystem.
    
            Change-Id: I870e59a14b6bcd8b45562cdd02c2502d60a9eeff
            Signed-off-by: liminghao <liminghao@xiaomi.com>
            From AOSP commit: 1206f6d8c5ed47ba19cfc30a19dba51fcd2cd5cb
    
            Signed-off-by: Theodore Ts'o <tytso@mit.edu>
    
        commit 2971e14beafea43d9428de2ffe98f8f42f4eb24e
        Author: liminghao <liminghao@xiaomi.com>
        Date:   Mon Apr 10 09:48:51 2017 +0800
    
            AOSP: blkid: Resolve to the exFAT uuid change on reboot.
    
            The volume_serial into exFAT super block is uuid but
            not standard uuid, it's just volume serial number.
    
            Change-Id: I376ed9fe1ba1b7f3d367d78cc5e2bb8ea9cc2d13
            Signed-off-by: liminghao <liminghao@xiaomi.com>
            From AOSP commit: 91e756e829362c66265334e2e20fb3604586ce8b
    
            Signed-off-by: Theodore Ts'o <tytso@mit.edu>
    
        commit 0c625fed12b1bbbe85a1c08846a2a24b8746a745
        Author: Upendra <upendra.baveja@sony.com>
        Date:   Thu Mar 1 17:15:48 2018 +0900
    
            AOSP: blkid: Correct the label name for exfat
    
            Volume label name is 16 bit unicode string according to spec.
            Currently blkid labels the device without converting it to
            utf-8 chars due to which incorrect label is displayed.
    
            Signed-off-by: Theodore Ts'o <tytso@mit.edu>
    
            Bug: 74184636
            Test: manual
            Change-Id: Ib16204c75c2cdf675d480e9c66f484bb3c51108e
            From AOSP commit: 25715073b170970469126426196c9e5084613c37
    
        commit 7525e8bc125702baf480717fe67e111e5ebb63cc
        Author: Theodore Ts'o <tytso@mit.edu>
        Date:   Tue Jul 30 21:13:44 2019 -0400
    
            libblkid: fix gcc -Wall warnings
    
            Google-Bug-Id: 118836063
    
            Signed-off-by: Theodore Ts'o <tytso@mit.edu>
    
    

    使用blkid的demo

    顺手记录下查找资料过程中看到的一个使用blkid的demo

    It's pretty much as simple as the manual makes it look: you create a probe structure, initialize it, ask it for some information, and then free it. And you can combine the first two steps into one. This is a working program:

    #include <stdio.h>
    #include <stdlib.h>
    #include <err.h>
    #include <blkid/blkid.h>

    int main (int argc, char *argv[]) { blkid_probe pr; const char *uuid;

    if (argc != 2) { fprintf(stderr, "Usage: %s devname\n", argv[0]); exit(1); }

    pr = blkid_new_probe_from_filename(argv[1]); if (!pr) { err(2, "Failed to open %s", argv[1]); }

    blkid_do_probe(pr); blkid_probe_lookup_value(pr, "UUID", &uuid, NULL);

    printf("UUID=%s\n", uuid);

    blkid_free_probe(pr);

    return 0; }

    blkid_probe_lookup_value sets uuid to point to a string that belongs to the pr structure, which is why the argument is of type const char *. If you needed to, you could copy it to a char * that you manage on your own, but for just passing to printf, that's not needed. The fourth argument to blkid_probe_lookup_value lets you get the length of the returned value in case you need that as well. There are some subtle differences between blkid_do_probe, blkid_do_safeprobe, and blkid_do_fullprobe, but in cases where the device has a known filesystem and you just want to pull the UUID out of it, taking the first result from blkid_do_probe should do.

    来自 https://stackoverflow.com/questions/6748429/using-libblkid-to-find-uuid-of-a-partition

    相关文章

      网友评论

          本文标题:Android Vold 随笔之e2fsprogs blkid

          本文链接:https://www.haomeiwen.com/subject/vqpzgktx.html