在Linux中从/proc文件系统获取硬件信息

4

我在C代码中使用execv来运行lshw命令以获取CPU、磁盘和内存信息。但我希望能够从/proc或任何其他已存在的数据中搜索到这些信息。有什么建议吗?以下是我的代码:

char *params[9]  = {"/usr/bin/lshw", "-short", "-c", "disk", 
                  "-c", "memory", "-c", "processor", 0}; //cmd params filled
execv(params[0], params);

Linux命令:$ sudo lshw -short -c disk -c processor -c memory

这个命令可以查看磁盘、处理器和内存的相关信息。请在终端中输入并运行此命令,以获取详细信息。

$ sudo lshw -short -c disk -c processor -c memory
H/W path         Device     Class          Description
======================================================
/0/0                        memory         64KiB BIOS
/0/22                       memory         16GiB System Memory
/0/22/0                     memory         DIMM Synchronous [empty]
/0/22/1                     memory         DIMM Synchronous [empty]
/0/22/2                     memory         8GiB DIMM Synchronous 2133 MHz (0.5 ns)
/0/22/3                     memory         8GiB DIMM Synchronous 2133 MHz (0.5 ns)
/0/2a                       memory         256KiB L1 cache
/0/2b                       memory         1MiB L2 cache
/0/2c                       memory         6MiB L3 cache
/0/2d                       processor      Intel(R) Xeon(R) CPU D-1521 @ 2.40GHz
/0/1/0.0.0       /dev/sda   disk           16GB SATADOM-SH 3IE3
/0/2/0.0.0       /dev/sdb   disk           120GB Patriot Blaze

我有两个问题:
  • 在哪里可以找到一个指南来解析/proc中的文件以获取这些硬件信息?
  • 我需要跟踪lshw的源代码才能找出lshw是做什么的吗?
编辑: 《高级Linux编程》第7章是解析/proc文件系统的指南。

4
阅读源代码比跟踪二进制代码更好。 - Ôrel
@jww 我的问题是关于如何在纯C代码编程中实现这一点。 - charles.cc.hsu
1
@Charles - 对不起,我应该更加注意。这可能有助于您的探索:lshw filetype:c - jww
一些信息位于“/sys/”下,而不仅仅是在“/proc/”下。 - Basile Starynkevitch
@BasileStarynkevitch,是的,你说得对。我刚刚发现lshw/sys/firmware/dmi/tables/读取原始数据,和dmidecode一样。而且dmidecode是用C写的,相对于lshw用CPP来说,C更容易些。 - charles.cc.hsu
3个回答

5

获取硬件信息的最佳方法是使用sysconf()和sysctl*()函数(Mac OS X、freebsd、openbsd),以及在Linux上使用sysconf()和sysinfo()。

解析/proc/*比调用sysinfo()或sysconf()更慢且更复杂。

下面是一个小例子,向您提供有关Mac OS X处理器和内存的一些信息:

#include <sys/types.h>
#include <sys/sysctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

int main()
{
 char *p = NULL;
 size_t len;
 sysctlbyname("hw.model", NULL, &len, NULL, 0);
 p = malloc(len);
 sysctlbyname("hw.model", p, &len, NULL, 0);
 printf("%s\n", p);
 /* CTL_MACHDEP variables are architecture dependent so doesn't work 
 for every one */
 sysctlbyname("machdep.cpu.brand_string", NULL, &len, NULL, 0);
 p = malloc(len);
 sysctlbyname("machdep.cpu.brand_string", p, &len, NULL, 0);
 printf("%s\n", p);
 int64_t mem;
 len = sizeof(mem);
 sysctlbyname("hw.memsize", &mem, &len, NULL, 0);
 printf("System Memory : %lld\n", mem);
 return (0);
}

您需要阅读man 3 sysctl,或在Linux上阅读man 2 sysconf和man 2 sysinfo。

一个有趣的链接:http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system#Other

您可以通过检索一些sysctl变量并自己进行计算(您可以在Google上找到公式)来计算CPU负载和使用情况。

但是如何找到物理DIMM信息,就像从$ sudo lshw -short -c memory报告中一样?

您可以在C程序中执行您的命令以将其保存为字符串,例如:

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>

char *strjoin(char *s1, char *s2, int n)
{
    int i = strlen(s2);
    int j = 0;
    if ((s2 = realloc(s2, (i + n + 1))) == NULL)
            perror(0);
    while (j < n && s1[j])
    {
            s2[i] = s1[j];
            i++;
            j++;
    }
    s2[i] = 0;
    return (s2);
}

int main()
{
    pid_t father;
    char buf[500] = {0};
    char *str;
    char *argv[5] = {"/usr/bin/lshw", "-short", "-c", "memory"};
    int fd[2];
    int ret;

    if (pipe(fd) == -1)
    {
            perror(NULL);
            return -1;
    }
    father = fork();
    if (father == 0)
    {
            close(fd[1]);
            while ((ret = read(fd[0], buf, 500)))
            {
                    str = strjoin(buf, str, ret);
            }
            close(fd[0]);
    }
    else
    {
            close(fd[0]);
            execv(argv[0], argv);
            close(fd[1]);
            wait(0);
    }
    wait(0);
    printf("%s", str);
    return 0;
}

在这段代码中,我没有检查所有函数的返回值,以免代码过长,但是在您的程序中应该这样做。

以下是解析文件/proc/meminfo并将我想要的两个字符串保存在双精度数组中,然后打印它们的示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    FILE *f;
    char *line = NULL;
    ssize_t read;
    size_t len = 0;
    char    **info;
    int i = 0;

    info = malloc(3 * sizeof(char*));
    f = fopen("/proc/meminfo", "r");
    while ((read = getline(&line, &len, f)) != -1)
    {
            if (strstr(line, "MemTotal") != NULL)
                    info[i] = strdup(line);
            else if (strstr(line, "MemFree") != NULL)
                    info[i] = strdup(line);
            i++;
    }
    info[i] = 0;
    fclose(f);
    i = 0;
    while (info[i])
    {
            printf("%s", info[i]);
            free (info[i]);
            i++;
    }
    free (info);
    return 0;
}

如果您想保存更多的字符串,请在双数组“info”中分配更多的空间,并在读取循环内部使用“else if”添加它们。 您可以使用“/ proc /”中的任何文件获取所需的信息。

是的,在Linux上,函数sysconf()和sysinfo()更好(man 2)。 在我给出的链接中,还有一个解析文件的示例,如果您的信息不全在这两个函数中。 - MIG-23
我已经阅读了man页面中的sysconf()和sysinfo()函数,并阅读了您提供的链接。但是我仍然无法得到我想要的信息。我将尝试阅读lsscsilscpu的代码,或者只需解析文件/proc/cpuinfo。但是在哪里可以找到物理DIMM信息,就像从$ sudo lshw -short -c memory报告中一样。 - charles.cc.hsu
你有访问 /dev/mem 的权限吗? - MIG-23
如果您需要帮助解析其中一个需要解析的文件,请在此粘贴其中一个文件内容,我将为您编写一个解析示例以获取所需信息。 - MIG-23
1
我修改了我的答案,最后展示了一个 C 语言保存命令结果的字符串示例(如果你运行此代码,它将输出该字符串)。你可以用任何想要的命令来实现这个功能。 - MIG-23
显示剩余2条评论

1
通过阅读lshw的源代码,我发现lshw/sys/class/dmi/读取原始数据。因为lshw是用CPP编写的,我不熟悉这个语言,所以有一个问题dmidecode从哪里获取SMBIOS表?提到dmidecode.c/sys/class/dmi读取与lshw相同的原始数据。
以下是dmidecode.c中的定义。
#define SYS_ENTRY_FILE "/sys/firmware/dmi/tables/smbios_entry_point"
#define SYS_TABLE_FILE "/sys/firmware/dmi/tables/DMI"

我从 dmidecode.c 中提取代码以获取CPU和内存信息,并使用 lsscsi 获取磁盘信息。
谢谢你的帮助。

-2

1:要获取CPU负载,请使用以下命令:

top -bn1 | grep load

这将会给你输出,例如:

top - 12:26:20 up 35 min,  2 users,  load average: 0.02, 0.01, 0.00

现在从上述字符串中解析出平均负载。 2:要获取内存信息,请使用此命令:

free -m

这将会给你:

total       used       free     shared    buffers     cached
Mem:         15926        308      15617          6         15        122
-/+ buffers/cache:        171      15755
Swap:            0          0          0

获取磁盘信息,请使用以下代码:
df -H /home/test

这将会给你:

Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1       102G  5.4G   91G   6% /

现在从上面的结果中解析出您想要的内容。


谢谢您的信息,但我想用纯C代码来实现。 - charles.cc.hsu
将上述命令的输出重定向到文件,然后从该文件解析数据。要进行重定向,请使用dup2()系统调用。例如:int fd = open(file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 然后复制输入/输出缓冲区的file_descriptor。例如:dup2(fd, 1); //将标准输出定向到文件和dup2(fd, 2); //将标准错误定向到文件。 - suraj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接