#!/usr/bin/perl -w
#
# (c) Bernhard Walle <bwalle@suse.de>
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; You may only use version 2 of the License, you have no option to
# use any other version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 675 Mass
# Ave, Cambridge, MA 02139, USA.
#

use POSIX ":sys_wait_h";
use Getopt::Long;

my $VERSION = "0.3.3";

###############################################################################
# Outputs usage information
sub usage
{
    print "kdump-copy_progress $VERSION\n";
    print "";
    print "Syntax:\n";
    print "    kdump-copy_progress [-l length] SOURCE DEST\n";
    print "\n";
    print "Options:\n";
    print "    -l length      Length in bytes of the stuff to copy\n";
}

###############################################################################
# Converts the size to mega bytes
sub to_mb
{
    my $size = shift;
    return $size / 1024.0 / 1024.0;
}

###############################################################################
# Shows the progress bar.
sub show_progress
{
    my $size = shift;
    my $current_size = shift;
    my $percentage = $current_size / $size;
    my $width = 40;
    my $oldflush = $|;

    $| = 1;

    my $stars = $percentage * $width;
    my $equals = $width - $stars;

    print "|";
    print "#" x $stars;
    print "-" x $equals;
    print "|  ";
    printf "%6d MB of %d MB (%2.1f%%)    \r", to_mb($current_size),
        to_mb($size), $percentage * 100;

    $| = $oldflush;
}

###############################################################################
# The main program

#
# parse command line
our ($print_help, $length);
GetOptions (
    'h|help' 				=> 	\$print_help,
    'l|length=s'			=>	\$length,
);
my $SOURCE = $ARGV[0];
my $DEST = $ARGV[1];

if ($print_help) {
    usage();
    exit 0;
}

if (!$SOURCE) {
    usage();
    exit 1;
}
if (!$DEST) {
    usage();
    exit 1;
}

if (! -r $SOURCE) {
    print "Source files doesn't exist.\n";
    exit(1);
}

#
# get the size of the source
my $src_size;

if (defined $length) {
    $src_size = $length;
} else {
    ($src_size) = (stat($SOURCE))[7];
    if (!$src_size || $src_size <= 0) {
        print "Source file is empty\n";
        exit 1;
    }
}

my $child_pid = fork();
if (!defined $child_pid) {
    die "Couldn't fork(): $!\n";
}

if ($child_pid > 0) {
    my $kid;
    $ret = 0;

    do {
        my $current_size;
        ($current_size) = (stat($DEST))[7];
        if (!defined $current_size) {
            $current_size = 0;
        }
        show_progress($src_size, $current_size);
        sleep 1;
        $kid = waitpid($child_pid, WNOHANG);
        $ret = $?;
    } while ($kid == 0);

    if ($ret == 0) {
        show_progress($src_size, $src_size);
    }
    print "\n";

    exit($ret != 0 ? 1 : 0);

} else {
    if (defined $length) {
        my $blocksize = 4096;
        my $firstlen = int($length / $blocksize); 
        my $rest = $length % $blocksize;
        my $skip = $length - $rest;

        system "dd if=$SOURCE of=$DEST bs=$blocksize ".
            "count=$firstlen status=noxfer &>/dev/null"
                and exit 1;
        if ($rest != 0) {
            my $offset = $length * $blocksize;
            system "dd if=$SOURCE of=$DEST bs=1 skip=$skip seek=$skip".
                " count=$rest status=noxfer &>/dev/null"
                and exit 1;
        }
    } else {
        exec "cp", ("--sparse=always", $SOURCE, $DEST);
    }
}


# vim: set sw=4 ts=4 et:
