Search code examples
clinuxmountioctlmount-point

Howto find the file for a loopmounted device?


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 ?


Solution

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