Howto find the file for a loopmounted device?
-
11-06-2021 - |
Question
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 ?
La solution 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;
}
Autres conseils
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.