【问题标题】:How can I get the devnode of a device using its file descriptor如何使用设备的文件描述符获取设备的 devnode
【发布时间】:2012-11-09 18:59:26
【问题描述】:

例如,我在一个设备数组中打开了 2 个设备..

节点是 /dev/ttyUSB0、/dev/ttyUSB1 等。

#define MAXDEV 4
devlist[MAXDEV];
const char *devices[] = {"/dev/ttyUSB0","/dev/ttyUSB1");


for(loop =0; loop<sizeof(devices); loop++){

    fd= open(devices[loop]);

}

现在我将它们添加到 fds 列表中;

for(i=0; i<MAXDEV; i++){

if(devlist[i] != 0){
devlist[i] = fd;
fd = -1;
}

}

现在我在设备上读取数据。

    for(iter=0; iter<MAXDEV; iter++){

if(FD_ISSET(devlist[iter],&fds)){

if ((nbytes = read(devlist[iter], buf, sizeof(buf)-1)) > 0 && nbytes != 0)
                    {

                 buf[nbytes] = '\0';

                     printf("Data Received on Node ???");

                    }
                if(nbytes < 0){
                            printf("connection reset\n");
                            FD_CLR(devlist[iter], &fds);
                            close(devlist[iter]);
                            devlist[iter] = 0;

                        }
                        if(nbytes ==0){
                            printf("Device Removed on Node ???\n");


                        FD_CLR(devlist[iter], &fds);
                            close(devlist[iter]);
                            devlist[iter] = 0;

                        }
    }
}

现在如何使用它的 fd 获取设备节点?...谢谢。

【问题讨论】:

  • 什么叫设备节点?你到底想得到什么,你有一个例子吗?
  • 您在寻找fstat(2)返回的设备ID吗?
  • 好吧,因为你不会知道删除了什么设备,所以我打算使用 fd 来获取设备节点。设备节点是插入设备的端口。例如。 /dev/ttyUSB0、/dev/ttyUSB1 等等。

标签: c linux


【解决方案1】:

正确的方法是自己记账。这将允许您完全按照用户提供的方式记录设备节点名称,而不是提供等效但令人困惑的不同名称。

例如,您可以使用hash table,将文件描述符编号与char 数组关联,并使用用于相应open() 调用的设备名称。

一个更简单但更脆弱且绝对推荐的解决方案可能涉及使用一个简单的指向char 的指针数组,其大小非常大,希望任何文件描述符值您可能会遇到可以用作适当字符串的索引而不会超出数组界限。这比哈希表编码稍微容易一些,但是如果文件描述符值超过字符串数组中允许的最大索引,它导致你的程序可怕地死掉。

如果您的程序无论如何都绑定到 Linux 平台,您也许可以,呃,作弊,方法是使用 /dev/fd 目录或 /proc 文件系统(更具体地说是 /proc/self/fd /dev/fd 通常是符号链接的目录)。两者都包含将文件描述符值与用于打开相应文件的路径的规范版本相关联的符号链接。例如考虑以下成绩单:

$ ls -l /proc/self/fd
total 0
lrwx------ 1 user user 64 Nov  9 23:21 0 -> /dev/pts/10
l-wx------ 1 user user 64 Nov  9 23:21 1 -> /dev/pts/10
lrwx------ 1 user user 64 Nov  9 23:21 2 -> /dev/pts/10
lr-x------ 1 user user 64 Nov  9 23:21 3 -> /proc/16437/fd/

您可以使用readlink() 系统调用来检索与感兴趣的文件描述符对应的链接目标。

【讨论】:

  • 谢谢,试试这个。
  • 我不认为 /proc/self/fd 包含指向 canonical 路径的符号链接;它只包含指向传递给open 的路径的符号链接。它没有任何规范。
  • @BasileStarynkevitch:我有理由确定路径在某种程度上是规范化的......例如/dev/fd显示为/proc/XXXX/fd......
  • 你错了。给定的 inode 可以有多个路径,也可以没有路径。这是 Unix 文件系统的语义。 /proc/ 伪文件系统只是 Linux 向用户级进程显示内核信息的方式。
  • @BasileStarynkevitch:我认为我们无缘无故地争论。当然,由于硬链接的存在,没有单一规范路径,但是在Unix上确实存在规范路径的概念;它是解析了所有符号链接的文件的绝对路径...例如,参见realpath(3) 手册页...
【解决方案2】:

您需要fstat(2) 系统调用,也许还需要fstatfs(2)。检查它是否成功。

  struct stat st;
  memset (&st, 0, sizeof(st));
  if (fstat (fd, &st))
    perror("fstat");
  else {
    // use st, notably st.st_rdev
  }

请记住,您可以拥有/dev 之外的设备。如果你确定你的设备在里面,你可以stat(2)里面的每个条目,并比较他们的st_rdev

另请阅读Advanced Linux Programming(它在免费许可下在线,但您可能想购买这本书)。

【讨论】:

  • 谢谢你试一试。
  • fstat 不起作用我得到一个错误的地址。 fstat(devlist[iter], buff);
  • 对不起,我错了,在打开的文件描述符上使用fstat。如果失败,检查errno buf 的第二个参数fstat 通常指向一个局部变量。
  • 它正在工作,但我得到的是数字。有没有办法让我获得设备节点?...例如。 /dev/ttyUSB0?.
  • 阅读一些关于 Linux 和 Unix 编程的书籍(了解一个文件可能有多个文件路径)。所以可能没有任何规范的文件路径。您可以扫描所有/dev/ 树并在内部的每个设备文件上使用fstatstat。不要将/dev/ttyUSB0称为设备节点,它只是一个文件路径。
【解决方案3】:

嗯,我可以看到这个问题大约 1 岁。但是现在我正在寻找一种方法来做到这一点。我找到了。要使用文件描述符获取设备节点,您可以结合 statlibudev 这是一个示例:

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <libudev.h>
#include <iostream>
#include <fcntl.h>


int main(int argc, char *argv[])
{
    struct stat sb;

    // Get a file descriptor to the file.
    int fd = open(argv[1], O_RDWR);

    // Get stats for that file descriptor.
    if (fstat(fd, &sb) == -1) {
        perror("stat");
        exit(EXIT_FAILURE);
    }

    // Create the udev context.
    struct udev *udev;
    udev = udev_new();

    // Create de udev_device from the dev_t obtained from stat.
    struct udev_device *dev;
    dev = udev_device_new_from_devnum(udev, 'b', sb.st_dev);

    // Finally obtain the node.
    const char* node  = udev_device_get_devnode(dev);

    udev_unref(udev);

    std::cout << "The file is in:    " << node << std::endl;

    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-22
    • 2011-12-24
    • 1970-01-01
    相关资源
    最近更新 更多