首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >获得二级存储大小的C代码

获得二级存储大小的C代码
EN

Stack Overflow用户
提问于 2016-10-03 06:50:51
回答 4查看 420关注 0票数 4

我需要一个简单的方法,以获得次要存储细节(如总大小,使用和空闲空间)在一个(守护进程)c代码的linux;

这就是我尝试过的

  • statvfs -不知道如何获取磁盘详细信息而不是文件
  • 使用系统(df -h

但是上面的内容涉及文件的写入和读取,这是不有效的,因为这个c代码是一个守护进程,它将不断地轮询系统的细节,作为图形生成的输入。

如果没有其他方法,请告诉我一个简单而快速的ipc机制,并举例说明这个bash和c代码之间的通信。

代码语言:javascript
运行
复制
/*
* @breif returns total percentage of secondary storage used
*
*   - uses bash command to get storage data and store in a file
*   - and use c code retrive the percent of usage from file and return it
*/
int calculate_storage_size( )
{
  if ( system("df -h --total | grep total > disk.stat") >= 0 )
  {
    char *temp_char_ptr = (char *)NULL;
    int storage_size_percent = -1;  
    FILE *fp ;
    fp = fopen ("disk.stat" , "r");
    if (fp != (FILE *)NULL)
    {
      temp_char_ptr = (char*) calloc ( 6 , 1 );
      fscanf( fp,"%s %s %s %s %d", temp_char_ptr, temp_char_ptr, temp_char_ptr, temp_char_ptr, &storage_size_percent);
    }
    free (temp_char_ptr);
    fclose(fp);
    return storage_size_percent;
  }
  return -1;
}

事先表示感谢和问候

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2016-10-03 12:48:12

我建议最好让用户指定在总数中应该考虑哪些挂载,或者使用启发式来省略系统和临时挂载。

考虑下面的示例,info.c

代码语言:javascript
运行
复制
#define  _POSIX_C_SOURCE 200809L
#define  _GNU_SOURCE
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/statvfs.h>
#include <mntent.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>

static void free_array(char **array)
{
    if (array) {
        size_t i;    
        for (i = 0; array[i] != NULL; i++) {
            free(array[i]);
            array[i] = NULL;
        }
        free(array);
    }
}

static char **normal_mounts(void)
{
    char         **list = NULL, **temp;
    size_t         size = 0;
    size_t         used = 0;
    char           buffer[4096];
    struct mntent  entry;
    FILE          *mounts;

    mounts = fopen("/proc/mounts", "r");
    if (!mounts)
        return NULL;

    while (getmntent_r(mounts, &entry, buffer, sizeof buffer) == &entry)
        if (strcmp(entry.mnt_fsname, "tmpfs") &&
            strcmp(entry.mnt_fsname, "swap")  &&
            strcmp(entry.mnt_dir, "/proc")    && strncmp(entry.mnt_dir, "/proc/", 6) &&
            strcmp(entry.mnt_dir, "/boot")    && strncmp(entry.mnt_dir, "/boot/", 6) &&
            strcmp(entry.mnt_dir, "/sys")     && strncmp(entry.mnt_dir, "/sys/", 5) &&
            strcmp(entry.mnt_dir, "/run")     && strncmp(entry.mnt_dir, "/run/", 5) &&
            strcmp(entry.mnt_dir, "/dev")     && strncmp(entry.mnt_dir, "/dev/", 5) &&
            strcmp(entry.mnt_dir, "/mnt")     && strncmp(entry.mnt_dir, "/mnt/", 5) &&
            strcmp(entry.mnt_dir, "/media")   && strncmp(entry.mnt_dir, "/media/", 7) &&
            strcmp(entry.mnt_dir, "/var/run") && strncmp(entry.mnt_dir, "/var/run/", 9)) {

            if (used >= size) {
                size = (used | 15) + 17;
                temp = realloc(list, size * sizeof list[0]);
                if (!temp) {
                    endmntent(mounts);
                    free_array(list);
                    errno = ENOMEM;
                    return NULL;
                }
                list = temp;
            }

            if (!(list[used++] = strdup(entry.mnt_dir))) {
                endmntent(mounts);
                free_array(list);
                errno = ENOMEM;
                return NULL;
            }
        }

    if (ferror(mounts) || !feof(mounts)) {
        endmntent(mounts);
        free_array(list);
        errno = EIO;
        return NULL;
    } else
        endmntent(mounts);

    if (!used) {
        free_array(list);
        errno = 0;
        return NULL;
    }

    if (size != used + 1) {
        size = used + 1;
        temp = realloc(list, size * sizeof list[0]);
        if (!temp) {
            free_array(list);
            errno = ENOMEM;
            return NULL;
        }
        list = temp;
    }

    list[used] = NULL;
    errno = 0;
    return list;
}

static int statistics(const char **mountpoint, uint64_t *bytes_total, uint64_t *bytes_free)
{
    struct statvfs  info;
    uint64_t        btotal = 0;
    uint64_t        bfree = 0;
    size_t          i;

    if (!mountpoint)
        return errno = EINVAL;

    for (i = 0; mountpoint[i] != NULL; i++)
        if (statvfs(mountpoint[i], &info) != -1) {
            btotal += (uint64_t)info.f_frsize * (uint64_t)info.f_blocks;
            bfree  += (uint64_t)info.f_bsize * (uint64_t)info.f_bavail;
        } else
            return errno;

    if (bytes_total)
        *bytes_total = btotal;
    if (bytes_free)
        *bytes_free = bfree;

    return 0;
}

int main(int argc, char *argv[])
{
    uint64_t total = 0;
    uint64_t nfree = 0;

    if (argc > 1) {
        if (statistics((const char **)argv + 1, &total, &nfree)) {
            fprintf(stderr, "%s.\n", strerror(errno));
            return EXIT_FAILURE;
        }
    } else {
        char **mounts = normal_mounts();
        size_t i;
        if (!mounts) {
            if (errno)
                fprintf(stderr, "Error determining file systems: %s.\n", strerror(errno));
            else
                fprintf(stderr, "No normal file systems found.\n");
            return EXIT_FAILURE;
        }
        fprintf(stderr, "Considering mount points");
        for (i = 0; mounts[i] != NULL; i++)
            fprintf(stderr, " %s", mounts[i]);
        fprintf(stderr, "\n");

        if (statistics((const char **)mounts, &total, &nfree)) {
            fprintf(stderr, "%s.\n", strerror(errno));
            return EXIT_FAILURE;
        }
        free_array(mounts);
    }

    printf("%20" PRIu64 " bytes total\n", total);
    printf("%20" PRIu64 " bytes free\n",  nfree); 
    return EXIT_SUCCESS;
}

statistics()函数接受一个以空结尾的挂载点数组,以及两个指向无符号64位整数的指针。如果函数成功,则返回0,否则返回非零errno代码。如果成功,函数将将文件系统中的总字节数设置为第一个整数,将第二个文件系统中的空闲字节数设置为第一个整数。

如果您提供一个或多个挂载点作为命令行参数,则只考虑这些参数。(POSIX表示argv[argc] == NULL,因此这种使用是安全的。)

否则,normal_mounts()函数将用于解析/proc/mounts以获得“正常”挂载点的列表。该函数使用getmntent()从内核提供的伪文件中读取每个条目(行)。排除了所有tmpfs (Ramdisk)和swap文件系统,以及安装在/proc/boot/sys/run/dev/mnt/media/var/run下的文件系统。这只是一个粗略的启发,而不是一个已知的好方法。

在守护进程中,甚至在图形应用程序中,您只调用(相当于) statistics()函数,并使用相同的挂载点数组。您甚至可以考虑分别跟踪每个挂载点,让用户过滤并组合他们感兴趣的信息。事实上,我建议这样做:我个人可能有兴趣看到我的临时文件使用(在/tmp/var/tmp是tmpfs挂载的机器上)的波动,以及跟踪我对/home的长期使用。

在守护进程中,您可以使用HUPUSR1USR2信号来指示用户希望您何时重新加载配置--此处的挂载点列表。我不认为将它集成到DBUS以检测可移动媒体挂载/卸载不会那么有趣,但是如果您认为它有用的话,当然可以。

如果您使用以下方法编译上述程序。

代码语言:javascript
运行
复制
gcc -Wall -O2 info.c -o info

然后跑

代码语言:javascript
运行
复制
./info

它将输出类似于

代码语言:javascript
运行
复制
Considering mount points / /home
        119989497856 bytes total
         26786156544 bytes free

其中第一行输出到标准错误,字节行输出到标准输出。您还可以专门命名挂载点--确保它们是不同的,因为代码没有检查是否有重复挂载--:

代码语言:javascript
运行
复制
./info /home /tmp

如果您想知道如何确定两个目录是否位于相同的挂载上:一个调用stat(path1, &info1),另一个调用stat(path2, &info2)。当且仅当(info1.st_dev == info2.st_dev)时,这两条路径在同一个挂载上。(一个设备可以在不同的点上多次安装,例如使用绑定安装,但通常上述检查就足够了。)

如果发现上述所有代码都很烦人,则可以始终依赖df实用程序。为确保输出位于C/POSIX区域(而不是法语或芬兰语),请使用

代码语言:javascript
运行
复制
handle = popen("LANG=C LC_ALL=C df -Pl", "r");

或者类似的,并使用len = getline(&line, &size, handle)读取输出。

票数 3
EN

Stack Overflow用户

发布于 2016-10-03 07:43:31

您可以使用popen()而不是system()/fopen():系统将在不使用硬盘的情况下为您提供一个可读的文件。

票数 3
EN

Stack Overflow用户

发布于 2016-10-03 07:42:05

除了系统和文件传说之外,没有任何可移植的ANSI C机制,甚至这也是一种幻想,因为它依赖于df的存在。但是,Posix函数popen()在本质上做了同样的事情,但是将输出作为文件*提供给您。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39825929

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档