Android Vold 随笔之e2fsprogs blkid

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351

推荐阅读更多精彩内容