demic0de
demic0de

Reputation: 1313

How can I get the devnode of a device using its file descriptor

For example I opened up 2 devices in an array of devices..

NODES are /dev/ttyUSB0, /dev/ttyUSB1 etc..

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


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

    fd= open(devices[loop]);

}

Now I add them to the list of fds;

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

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

}

Now I read on the devices for data.

    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;

                        }
    }
}

Now how do I get the device node using its fd?.. Thanks.

Upvotes: 1

Views: 3958

Answers (3)

Raydel Miranda
Raydel Miranda

Reputation: 14360

Well I can see this question is about 1 year old. But right now I was looking for a way of doing this. And I found it. For getting the device node using the file descritor you can combine stat and libudev here is an example:

#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;
}

Upvotes: 1

thkala
thkala

Reputation: 86323

The proper way to do this is to do your own book-keeping. That would allow you to log the device node name exactly as supplied by the user, rather than provide an equivalent, yet confusingly different one.

For example you could use a hash table, to associate file descriptor numbers to char arrays with the device name used for the corresponding open() call.

A simpler, but far more fragile and definitely not recommended, solution might involve using a simple array of pointers to char with an inordinately large size, in the hopes that any file descriptor value that you may encounter can be used as an index to the appropriate string without going beyond the array bounds. This is slightly easier to code than a hash table, but it will cause your program to die horribly if a file descriptor value exceeds the maximum allowed index in your string array.

If your program is bound to the Linux platform anyway, you might be able to, uh, cheat by using the /dev/fd directory or the /proc filesystem (more specifically the /proc/self/fd directory to which /dev/fd is usually a symbolic link). Both contain symbolic links that associate file descriptor values to canonical versions of the paths that where used to open the corresponding files. For example consider the following transcript:

$ 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/

You can use the readlink() system call to retrieve the target of the link that corresponds to a file descriptor of interest.

Upvotes: 1

You need the fstat(2) syscall, perhaps also fstatfs(2). Check that it succeeded.

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

Remember that you could have a device outside of /dev. If you are sure that your device is in it, you could stat(2) every entry in it, and compare their st_rdev

Read also Advanced Linux Programming (it is online under a free license, but you may want to buy the book).

Upvotes: 0

Related Questions