#!/usr/bin/perl
use strict;
use integer;
sub error {
print STDERR "@_\n";
exit -1;
}
sub err_usage() {
error "Usage: $0 vdifile mountpoint [partition]";
}
sub exec_cmd {
my $cmdstr="@_";
my $status=system $cmdstr;
if($status != 0) {
my $cmdstr="sudo @_";
my $status=system $cmdstr;
}
return $status;
}
sub exec_cmd_pipe {
my $fd;
open( FD, "@_ |" ) or open( FD, "sudo @_ |" ) ;
$fd=\*FD;
return $fd;
}
sub vdi_info($) {
my $vdifile=shift;
my $info={};
my $fd=exec_cmd_pipe "vdiinfo", $vdifile;
my $key;
my $line="";
my $prevline="";
while(<$fd>) {
chomp $_;
if(/^\s*([^:]+):\s+(.*)$/) {
$key=$1;
$info->{$key}=$2;
} else {
$info->{$key}=$info->{$key}."\n".$_;
}
}
close $fd;
return $info;
}
sub loop_info() {
my $info={};
my $fd=exec_cmd_pipe "losetup", "-a";
while(<$fd>) {
chomp $_;
if(/^\s*([^:]+):.*$/) {
my $loopdev=$1;
$info->{$loopdev}="true";
}
}
close $fd;
return $info;
}
sub part_info($) {
my $drive=shift;
my $fd=exec_cmd_pipe "fdisk", "-l", "-u", $drive;
my $info={};
while(<$fd>) {
chomp $_;
if(/^\s*([^\s]+)\s+(\*?)\s+(\d+)\s+(\d+)\s+(\d+)(\+?)\s+([^\s]+)\s+(.*)$/) {
my $device=$1;
$info->{$device}={};
$info->{$device}->{"start"}=$3;
$info->{$device}->{"end"}=$4;
$info->{$device}->{"bootable"}=0;
if($2 =~ /^\*$/) {
$info->{$device}->{"bootable"}=1;
}
$info->{$device}->{"id"}=$7;
}
}
close $fd;
return $info;
}
sub unset_loopdev($) { my $mount_dev=shift; exec_cmd "losetup", "-d", $mount_dev; }
sub set_loopdev { my $mount_dev=shift; my $mount_file=shift; exec_cmd "losetup", $mount_dev, $mount_file, @_; }
sub mount { exec_cmd "mount", @_; }
sub main {
my $vdifile=shift;
my $mountpoint=shift;
my $part=shift || 1;
if(! $vdifile || !$mountpoint) {
err_usage;
}
if ( ! -f $vdifile) {
error "File: $vdifile not found or not a file";
}
if ( ! -d $mountpoint) {
error "Mountpoint: $mountpoint not found or not a directory";
}
my $vdiinfo;
$vdiinfo=vdi_info $vdifile;
if(!$vdiinfo) { error "Unable to recover VDI file information"; }
{
my $vditype=$vdiinfo->{"Image Type"};
if ($vditype != "FIXED") {
error "VDI is not a flat file, it can not be mounted";
}
}
my $offset=$vdiinfo->{"Offset Data"};
my $partinfo;
{
my $loopinfo=loop_info;
if(!$loopinfo) { error "Unable to recover loopback information"; }
my $loopdev, my $i=0, my $loopprefix="/dev/loop";
while(1) {
$loopdev=$loopprefix.$i;
if($loopinfo->{$loopdev}) {
print STDERR "$loopdev not available.\n";
} else {
if(! -e $loopdev) {
error "No loop device available at the moment.";
} else {
set_loopdev $loopdev, $vdifile, "-o", $offset;
$partinfo=part_info $loopdev;
unset_loopdev $loopdev;
last;
}
}
$i=$i+1;
}
if(!$partinfo) { error "Unable to recover paritition information"; }
if(!$partinfo->{$part}) { $part=$loopdev."p".$part; }
if(!$partinfo->{$part}) { error "Partition information not available for: $part"; }
}
{
my $vdisectorsize=$vdiinfo->{"Sector Size"};
my $vdisectorstart=$partinfo->{$part}->{"start"};
$offset=$offset+($vdisectorsize*$vdisectorstart);
}
mount "-o", "loop,offset=$offset", $vdifile, $mountpoint, "2>/dev/null";
}
main @ARGV;