All pastes #1297025 Raw Edit

Guilt

public text v1 · immutable
#1297025 ·published 2008-12-31 10:37 UTC
rendered paste body
#!/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;