如何从 linux 拉取 SD 卡的挂载和 df 信息?

How to pull mount and df information for SD card from linux?

我正在 运行 在 Linux 内核上安装一个嵌入式软件(用 C 语言编写)。我需要在我的软件上创建一个警报,检查是否安装了 SD 卡,并找出它的容量。我可以集思广益三个想法:

  1. 我正在考虑读取和解析文件/proc/mounts

    然后,使用 regex 和一堆字符串比较来检查是否存在任何 SD 卡,或者

  2. 使用dirent库扫描并检查/mnt/下的首选目录名称。

    无论哪种方式,我都不确定如何获取 SD 卡上的内存使用情况,或者

  3. 我可以使用我的软件 运行 包含 df 命令的 shell 脚本,输出到文件中,然后读取它。它应该告诉我是否有 SD 卡,它安装在什么地方,以及它的容量。

我相信有很多简单直接的方法可以获取这些信息并将其输入到我的软件中。也许是一个漂亮的图书馆电话?我做了一些研究并在 fstab<sys/mount.h> 上看到了资源,我认为这些不会带我走得更远。有没有人有更好的想法?

我知道你没有要求代码,但你可以(我写得很开心)。

#include <stdio.h>

#include <dirent.h>
#include <limits.h>

#include <string.h>

#include <unistd.h>
#include <fcntl.h>

#include <stdlib.h>
#include <sys/stat.h>

static int
walkdir(const char *const path, int (*visit)(const char *const, const char *const), void *data)
{
    struct dirent *entry;
    DIR *dir;
    dir = opendir(path);
    if (dir == NULL)
        return -1;
    while ((entry = readdir(dir)) != NULL) {
        int code;
        code = visit(path, entry->d_name);
        if (code != 0) {
            closedir(dir);
            return code;
        }
    }
    closedir(dir);
    return 0;
}

static char *
file_get_content(const char *const path)
{
    int file;
    struct stat st;
    char *text;
    size_t size;

    text = NULL;
    file = -1;
    if (stat(path, &st) == -1)
        goto error;
    size = st.st_size;
    text = malloc(size + 1);
    if (text == NULL)
        goto error; // file too large, cannot read like this
    file = open(path, O_RDONLY);
    if (file == -1)
        goto error;
    if ((size = read(file, text, size)) <= 0)
        goto error;
    text[size] = '[=10=]';
    if (file != -1)
        close(file);
    return text;
error:
    if (file != -1)
        close(file);
    free(text);
    return NULL;
}

static size_t
get_size(const char *const dirpath, const char *const name)
{
    char path[PATH_MAX];
    char *text;
    int length;
    size_t size;

    length = snprintf(path, sizeof(path), "%s/%s/size", dirpath, name);
    if (((size_t) length) > sizeof(path))
        return 0;
    size = 0;
    text = file_get_content(path);
    if (text != NULL) { 
        size = strtoll(text, NULL, 10);
        free(text);
    }
    return size;
}

static int
display_block(const char *const dirpath, const char *const name)
{
    const char *block;
    block = strrchr(dirpath, '/');
    if (block == NULL)
        return -1;
    block += 1;

    if (strstr(name, block) == name) {
        size_t size;
        // get_ the parition size
        //
        // Note, I had to divice the size by 2 because it didn't
        // match the sizes reported by `df'.
        //
        // Also, it appears that it's in megabytes 
        // (i.e. twice the size in MB)
        size = get_size(dirpath, name) / (1 << 21);
        // Display the result
        fprintf(stdout, "\tpartition: %s (%zu GB)\n", name, size);
    }

    return 0;
}

static char *
get_vendor(const char *const name)
{
    char path[PATH_MAX];
    int length;
    char *value;
    // get_ partitions
    length = snprintf(path, sizeof(path), "/sys/block/%s/device/vendor", name);
    if (((size_t) length) > sizeof(path))
        return NULL;
    value = file_get_content(path);
    if (value == NULL)
        return NULL;        
    // Make the trailing `\n' a '[=10=]' instead
    strtok(value, "\n");
    return value;
}

static char *
get_model(const char *const name)
{
    char path[PATH_MAX];
    int length;
    char *value;
    // get_ partitions
    length = snprintf(path, sizeof(path), "/sys/block/%s/device/model", name);
    if (((size_t) length) > sizeof(path))
        return NULL;
    value = file_get_content(path);
    if (value == NULL)
        return NULL;        
    // Make the trailing `\n' a '[=10=]' instead
    strtok(value, "\n");
    return value;
}

static int
parse_block(const char *const name)
{
    char path[PATH_MAX];
    int length;
    char *vendor;
    char *model;
    // get_ partitions
    length = snprintf(path, sizeof(path), "/sys/block/%s", name);
    if (((size_t) length) > sizeof(path))
        return -1;      
    vendor = get_vendor(name);
    model = get_model(name);    
    if ((model != NULL) && (vendor != NULL)) {
        fprintf(stdout, "block device: %s (%s %s)\n", name, vendor, model);
        walkdir(path, display_block, NULL);
    }
    free(vendor);
    free(model);
    return 0;
}

static int
list_devices(const char *const dirpath, const char *const name)
{
    if (*name == '.')
        return 0;
    parse_block(name);
    return 0;
}

int
main(void)
{
    return walkdir("/sys/block", list_devices, NULL);
}

这将向您展示设备及其相关信息,以及您非常感兴趣的尺寸。

请注意,不需要安装它们。

您当然可以在其他地方找到更多信息。只需检查相应的目录,您就可以获得所有内容。例如,有一个文件 removable 告诉您设备是否可移动,我认为这对您的情况非常有用。

我已经使用statfs()系统调用获取SD卡容量和使用情况。 至于检测卡的存在,我使用 stat() 调用在 /mnt/sd_card_dir 处寻找首选目录,其中 sd_card_dir 在自动安装配置期间设置。如果存在,则 SD 卡(很可能)存在 - 因为 sd_card_dir 文件夹会在插入 SD 卡时自动创建。如果您创建分区,它们应该显示为 sd_card_dir 的子目录。

应调用以下库:

#include <sys/stat.h>
#include <sys/vfs.h>

以下函数处理检测,需要定期调用 - 至少每分钟一次。在我的特殊情况下,我每 10 秒调用一次此函数作为低优先级任务并附加到软件的主循环。

#define PATH "/mnt/sd_card_dir"
static int handler_sd_card_status(void)
{
    struct stat st;
    struct statfs fs;

    if (stat(PATH, &st))
        printf("Missing or unreadable\n");
    else {
        if (!statfs(PATH, &fs)) {
            char sd_stat[32];
            double scale = fs.f_bsize / 1e9;
            snprintf(sd_stat, sizeof(sd_stat),
                "%.2f of %.1f GB used",
                (fs.f_blocks - fs.f_bavail) * scale,
                fs.f_blocks * scale);
            printf("%s\n", sd_stat);
        } else
            printf("Size unreadable\n");
    }
    return 0;
}