#!/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;