Pregunta

Question:

if I loopmount a file, like this

mount /volumes/jfs.dsk /mnt/jfs -t jfs -o loop

then what happens behind the scenes is

losetup /dev/loop1 /volumes/jfs.dsk
mount /dev/loop1 /mnt/jfs -t jfs -o loop

My question now:
If I have /dev/loop1, how can I find which file this device belongs to ?
e.g. given "/dev/loop1" as input, how can I get back /volumes/jfs.dsk ?

¿Fue útil?

Solución 3

Since nobody knew the concrete answer, I answer it here as reference for others:

public static string loopfile_from_sysfs(string device)
{
    string res = null;
    Mono.Unix.Native.Stat st;
    System.IntPtr f;

    //if (stat(device, &st) || !S_ISBLK(st.st_mode))
    //if (System.Convert.ToBoolean(Mono.Unix.Native.Syscall.stat(device, out st)) || !S_ISBLK((int) st.st_mode))
    //  return null;

    Mono.Unix.Native.Syscall.stat(device, out st);

    const string _PATH_SYS_DEVBLOCK = "/sys/dev/block";
    string strPath = string.Format("{0}/{1}:{2}/loop/backing_file", _PATH_SYS_DEVBLOCK, gnu_dev_major(st.st_rdev), gnu_dev_minor(st.st_rdev));

    f = Mono.Unix.Native.Syscall.fopen(strPath, "r");
    if (f == IntPtr.Zero)
        return null;

    Mono.Unix.Native.Syscall.fclose(f);

    res = System.IO.File.ReadAllText(strPath);
    strPath = null;
    return res;
} // End Function loopfile_from_sysfs


public static string loopdev_get_loopfile(string device)
{
    string res = loopfile_from_sysfs(device);

    if (res == null)
    {
        loop_info lo = new loop_info();
        loop_info64 lo64 = new loop_info64();

        int fd;

        if ((fd = Mono.Unix.Native.Syscall.open(device, Mono.Unix.Native.OpenFlags.O_RDONLY)) < 0)
            return null;

        if (UnsafeNativeMethods.ioctl(fd, LOOP_GET_STATUS64, ref lo64) == 0)
        {
            //lo64.lo_file_name[LO_NAME_SIZE-2] = '*';
            //lo64.lo_file_name[LO_NAME_SIZE-1] = 0;
            //res = strdup((char *) lo64.lo_file_name);
            res = lo64.lo_file_name;
            Console.WriteLine("LOOP_GET_STATUS64");

        }
        else if (UnsafeNativeMethods.ioctl(fd, LOOP_GET_STATUS, ref lo) == 0)
        {
            //lo.lo_name[LO_NAME_SIZE-2] = '*';
            //lo.lo_name[LO_NAME_SIZE-1] = 0;
            //res = strdup((char *) lo.lo_name);
            res = lo.lo_name;
            Console.WriteLine("LOOP_GET_STATUS");
        }

        Mono.Unix.Native.Syscall.close(fd);
    } // End if (res == null)

    return res;
} // End Function loopdev_get_loopfile

And this is the C version:

static char *loopfile_from_sysfs(const char *device)
{
    FILE *f;
    struct stat st;
    char buf[PATH_MAX], *res = NULL;
    // PATH_MAX: 4096

    if (stat(device, &st) || !S_ISBLK(st.st_mode))
        return NULL;

    #define _PATH_SYS_DEVBLOCK "/sys/dev/block"
    snprintf(buf, sizeof(buf), _PATH_SYS_DEVBLOCK "/%d:%d/loop/backing_file",
            major(st.st_rdev), minor(st.st_rdev));

    f = fopen(buf, "r");
    if (!f)
        return NULL;

    if (fgets(buf, sizeof(buf), f)) {
        size_t sz = strlen(buf);
        if (sz) {
            buf[sz - 1] = '\0';
            res = strdup(buf);
        }
    }

    fclose(f);

    printf("loopfile_from_sysfs Result: %s\n", res);
    return res;
}



char *loopdev_get_loopfile(const char *device)
{
    char *res = loopfile_from_sysfs(device);

    if (!res) {
        struct loop_info lo;
        struct loop_info64 lo64;
        int fd;

        if ((fd = open(device, O_RDONLY)) < 0)
            return NULL;

        if (ioctl(fd, LOOP_GET_STATUS64, &lo64) == 0) {
            lo64.lo_file_name[LO_NAME_SIZE-2] = '*';
            lo64.lo_file_name[LO_NAME_SIZE-1] = 0;
            res = strdup((char *) lo64.lo_file_name);
            printf("LOOP_GET_STATUS64\n");

        } else if (ioctl(fd, LOOP_GET_STATUS, &lo) == 0) {
            lo.lo_name[LO_NAME_SIZE-2] = '*';
            lo.lo_name[LO_NAME_SIZE-1] = 0;
            res = strdup((char *) lo.lo_name);
            printf("LOOP_GET_STATUS\n");
        }
        close(fd);
    }
    return res;
}

Otros consejos

I think calling:

strace losetup /dev/loop1

and then googling will give you answer.

From what I've seen on my PC, to get status of loopback device ioctl 0x4c05 is called.

From losetup(8) man page

If only the loopdev argument is given, the status of the corresponding loop device is shown.

So you only need to use

$ losetup /dev/loop1
/dev/loop1: [0802]:4751362 (/volumes/jfs.dsk)

If you have a recent kernel (2.6.37 or above), you can also get the target file in /sys/block/loopX/loop/backing_file.

$ cat /sys/block/loop1/loop/backing_file
/volumes/jfs.dsk

If you want to do that problematically (you did not clearly indicate that but you have added the c tag), you should use the LOOP_GET_STATUS or LOOP_GET_STATUS64 ioctl call.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top