#!/usr/bin/perl
#
# Title:   cdrecord_progressbar.pl
# Purpose: burn data to CD, print progress in *.
#
# Kill any previous running mkisofs or cdrecord
#
system('pkill', '-15', 'mkisofs');
system('pkill', '-15', 'cdrecord');
#####################################################
# Get options passed to script
#####################################################
use Getopt::Long;
GetOptions(
    "A=s" => \$ApplicationLabel,
    "V=s" => \$VolumeLabel,
    "debug!" => \$Debug,
    "h!" => \$help,
);
#####################################################
# Print usage and exit if -h was passed
if ( $help )
{
 print "Usage: cdrecord_progressbar.pl -A App -V MyData <list of dirs to burn separated by spaces>\n"
      ."Arguments (A and V) are optional.\n"
      ."-A (app) default to 'ogg'.\n"
      ."-V (vol label) defaults to my_data.<Date:YYYYMMDD.HHMM>.\n"
      ."--debug activates extra debug output.\n"
      ."-h prints this help message.\n" ;
  exit ;
}
#####################################################
# Print usage and exit if -h was passed
if ( $Debug )
{
    print "***** DEBUG MODE *****\n"; 
}
#####################################################
# If App Label wasn't set, set default name.
if ( ! $ApplicationLabel )
{
	$ApplicationLabel="App";
} else {
   chomp($ApplicationLabel);
}
if ( $Debug ){ print "ApplicationLabel:$ApplicationLabel\n";  }
#####################################################
# If Volume Label wasn't set, set default name.
if ( ! $VolumeLabel ) 
{ 
    my $Date=`date +%Y%m%d.%H%M`;
    $VolumeLabel="my_data.$Date";
    chomp($VolumeLabel); 
} else {
    chomp($VolumeLabel); 
}
if ( $Debug ){ print "VolumeLabel:$VolumeLabel\n"; }
#####################################################
# Directories to be burned
# If No Directories specified, burn /data
# Calculate size
# IF size is too small, progress bar won't work.
#####################################################
use File::Find;
my $Directories;
my $sum=0;    #<- raw return value from calculation
my $total=0;  #<- used later for calculation
if ( @ARGV  ){
   # Convert each element to string
   # Place single quotes around each element
   for my $i (@ARGV)
   {
       $Directories=$Directories."\'$i\' "; 
   }
   find sub { $sum += -s }, @ARGV;
} else {
   $Directories="/data";
   find sub { $sum += -s }, ($Directories);
}
my $total=int($sum/1048576);
if ( $Debug ){ print "Directories:$Directories\n"; }
if ( $Debug ){ print "Total Size:$total\n"; }
#
# If $total too small, dont' bother with progress bar
# Print something like finishing soon.
#
if ( $total <= 2 )
{ 
    print "Data size too small for progress bar\n";
    print "Finishing soon.  Please wait.\n";
}    
#####################################################
# Validate CD media for burn
# If cd has recoginzed file system, vol_id will exit value 0
# If it does not, vol_id returns non-zero
#####################################################
my $Bad_disk=0;
open (CHECKDISK, "/lib/udev/vol_id -t /dev/cdrw 2>&1 |") || die "Cannot Checkdisk: $!\n";
while (<CHECKDISK>)
{
    if ( $Debug ){ print "$_\n"; }
    if ( $_ =~ m/iso9660/)
    {
        print "[ !! ]  CD Not Blank. Please insert a blank CD.\n";
        $Bad_disk=1;
    } 
    elsif ( $_ =~ m/.*error\ opening\ volume/)
    {
        print "[ !! ]  No Disk. Please insert a blank CD.\n";
        $Bad_disk=1;
    } 
    elsif ( $_ =~ m/.*unknown\ volume\ type/)
    {
        if ( $Debug ){ print "[ OK ]  Found Blank Disk!\n"; }
        $Bad_disk=0;
    }
    else {
        print "[ !! ]  Unidentified Error. Please insert a blank CD.\n";
        print "ERROR: $_\n";
	$Bad_disk=1;
    }
    # Eject and exit if disk is bad.
    if ( $Bad_disk == 1  )
    {
     open (EJECT, "/usr/bin/eject |") || die "Cannot Eject: $!\n" ; 
        close (EJECT) || die "Cannot end eject command: $!\n" ;
        exit;
    }
}
# Closing fiel handle doesn't work
close (CHECKDISK);
#####################################################
# Burn
#####################################################
if ( $Debug ){ print "Begin Burn\n"; }
#
# Shell Command
#
#my $cmd_test="/usr/bin/cdrecord -v -dummy dev=/dev/cdrw ./asic_install_cd.iso 2>/dev/null";
my $cmd="/usr/bin/mkisofs -J -R -A \'$ApplicationLabel\' -V \'$VolumeLabel\' $Directories 2>/dev/null | /usr/bin/cdrecord -v  -dummy  speed=8 dev=/dev/cdrw -tao -eject - 2>/dev/null";
# cdrecord output's progress with \r as end of line
# We need to make <> use \r instead of \n
local $/ = "\r";
#
# Turn on autoflush, or '*' will not print until burn process ends
#
local $| = 1;
#
# Percent complete from last round
#
my $last_round = 0;
#
# Percent complete for this round
#
my $percent = 0;
#
# Launch the  Shell Command.
#
open (CMD, "$cmd |");
while (<CMD>) {
    #
    # Parsing Data in Format:  Track 01:    6 MB written (fifo 100%) [buf  99%]   8.2x.
    #
    if ( $_ =~ m/^Track\ 01.*\ (\d+)\ MB.*/ ) {
           #
	   # Holds current
           #
	   my $current = $1;
           #
	   # Skip if $total is too small (avoid division by zero)
	   #
	   if ( $total > 0 )
           {  
	        # 
		# Calculate percent complete
		#
		$percent = int( 100 * $current / $total );

                if ( $Debug ){ print "$current/$total = $percent %\n"; };

     		#
     		# If we increated the number of dots, add that many dots.
     		#
     		if ( $percent > $last_round ) {
     		    my $add_dots = $percent - $last_round;
     		    print "*"x$add_dots;

     		    # Store current progress
     		    $last_round = $percent;
     		}
	   }
    }
    if ( $percent >= 99 )
    {
        print "Finishing disk\n";
    }
}

