blob: b4c9fba3bcec04a068423d5ed5cb42044fcbe71a [file] [log] [blame]
#include "kvm/disk-image.h"
#include <linux/err.h>
#include <mntent.h>
/*
* raw image and blk dev are similar, so reuse raw image ops.
*/
static struct disk_image_operations blk_dev_ops = {
.read = raw_image__read,
.write = raw_image__write,
.wait = raw_image__wait,
.async = true,
};
static bool is_mounted(struct stat *st)
{
struct stat st_buf;
struct mntent *mnt;
FILE *f;
f = setmntent("/proc/mounts", "r");
if (!f)
return false;
while ((mnt = getmntent(f)) != NULL) {
if (stat(mnt->mnt_fsname, &st_buf) == 0 &&
S_ISBLK(st_buf.st_mode) && st->st_rdev == st_buf.st_rdev) {
fclose(f);
return true;
}
}
fclose(f);
return false;
}
struct disk_image *blkdev__probe(const char *filename, int flags, struct stat *st)
{
int fd, r;
u64 size;
if (!S_ISBLK(st->st_mode))
return ERR_PTR(-EINVAL);
if (is_mounted(st)) {
pr_err("Block device %s is already mounted! Unmount before use.",
filename);
return ERR_PTR(-EINVAL);
}
/*
* Be careful! We are opening host block device!
* Open it readonly since we do not want to break user's data on disk.
*/
fd = open(filename, flags);
if (fd < 0)
return ERR_PTR(fd);
if (ioctl(fd, BLKGETSIZE64, &size) < 0) {
r = -errno;
close(fd);
return ERR_PTR(r);
}
/*
* FIXME: This will not work on 32-bit host because we can not
* mmap large disk. There is not enough virtual address space
* in 32-bit host. However, this works on 64-bit host.
*/
return disk_image__new(fd, size, &blk_dev_ops, DISK_IMAGE_REGULAR);
}