#!/usr/bin/perl -w
use strict;

#
# Partimage Is Not Ghost / rc.ping
#
# Copyright(c) 2005 SysAngel
# Home page: PING (Partimage Is Not Ghost) http://ping.windowsdream.com/
#
# This script is intended to run on a RIP (Recovery Is Possible) Linux-live
# image. As for RIP, Linux, GNU/GPL tools, etc. refer to specific licences.
# This script (rc.ping) has been written by Fabrice Scemama (the Author),
# from SysAngel. Email: fabrice@sysangel.com .
# * Use it at your own risk. No warranty, no damage accountability.
# * You should not remove this copyright, nor modify the script without
#   the agreement of the Author, nor redistribute it apart from a complete
#   PING package distribution.
# * You may link to http://ping.windowsdream.com/ but not set up a
#   download mirror without the agreement of the Author.
# * Please, refer any bug / feature request to the Author.
#

my $VERSION = "1.10";

my %P = ();


# Give the user a chance to avoid this script.
#
print "\n\n*** PING (Partimage Is Not Ghost) -- version $VERSION ***\n\n";
print "Type [ENTER] to go on, x to get a shell (RIP Distribution).\n";
{
    my $Grab = <STDIN>;
    if($Grab =~/^x/i)
    {
        exit;
    }
}


# Preliminaries
#
unless(-d "/tmp")
{
    mkdir("/tmp", 1777);
}
if(-e "/tmp/x.log")
{
    unlink("/tmp/x.log");
}


# The source.
#
my $SRC = "";


# Try to mount the CDRom and find there an image.
#
{
    my $nb = 0;
    foreach("hda", "hdb", "hdc", "hdd", "sda", "sdb", "sdc", "sr0")
    {
        system("umount /mnt/cdrom >/dev/null 2>&1");
        system("mount /dev/$_ /mnt/cdrom >/dev/null 2>&1");
        my $nb = `mount|grep cdrom|wc -l`;
        if($nb > 0) {
            LOG("* Found and mounted a CDRom\n");
            opendir(DIR, "/mnt/cdrom");
            my(@Files) = readdir(DIR);
            closedir(DIR);
            foreach my $F (@Files) {
                if($F =~/^.da$/) {
                    LOG("* Found /mnt/cdrom/$F\n");
                    $SRC = "/mnt/cdrom";
                }
            }
            sleep 10;   # Blink & start up.
            last;
        }
    }
    unless($nb) {
        LOG("* No CDRom device or media was found.\n");
    }
}


# Give a warm welcome to the user...
#
{
    my $cmd = 'dialog --colors --msgbox "\Zb\Z7Welcome to PING (Partimage Is'
        .' Not Ghost!\n\n\n'
        .'\ZnThis tool can be used both to backup a Ghost-like image of'
        .' your hard disk and to restore your hard disk from such an image.'
        .' Please, be aware that if you choose to restore your hard disk,'
        .' ALL the data contained on this computer will be '
        .'lost during the restoration. You may choose to abort now, by '
        .'stopping the computer now.\n\n\n" 22 73';
    system($cmd);
}


# If there's no CD, or no image within the CD, then try the network.
#
unless($SRC) {
    my $out = `ifconfig |grep ^eth |wc -l 2>&1`;
    $out =~s/\D//g;
    if($out == 0)
    {
        LOG("\n* Getting a DHCP IP address...\n");
        `dhcpcd eth0`;
    }
    $out = `ifconfig |grep ^eth |wc -l 2>&1`;
    $out =~s/\D//g;
    if($out == 0)
    {
        LOG("\n!!! Could not find a network device and connect it to DHCP.\n");
        #
	# Let's ask the user for help...
	#
	my %N = ();
        my $Try_Again = 1;

        while($Try_Again) {
            foreach("IP", "Netmask", "Gateway") {
                $N{$_} = "";
            }

            my $cmd = 'dialog --inputbox "Enter your IP address '
                .'(eg. 192.168.0.10)" 8 51 2>/tmp/BLA';
            system($cmd);
            open(DB, "/tmp/BLA");
            while(<DB>) {
                $N{IP} .= $_;
            }
            close(DB);

            $cmd = 'dialog --inputbox "Enter your netmask '
                .'(eg. 255.255.255.0)" 8 51 2>/tmp/BLA';
            system($cmd);
            open(DB, "/tmp/BLA");
            while(<DB>) {
                $N{Netmask} .= $_;
            }
            close(DB);

            $cmd = 'dialog --inputbox "Enter your gateway '
                .'(eg. 192.168.0.1)" 8 51 2>/tmp/BLA';
            system($cmd);
            open(DB, "/tmp/BLA");
            while(<DB>) {
                $N{Gateway} .= $_;
            }
            close(DB);

            foreach("IP", "Netmask", "Gateway") {
		$N{$_} =~s/^\s*//;
		$N{$_} =~s/\s*$//;
		$N{$_} =~s/[^0-9.]//g;
            }

	    LOG("* Connecting to the network\n");
	    system("ifconfig eth0 down; ifconfig eth0 $N{IP} netmask $N{Netmask} up;"
		   ." route add default gw $N{Gateway}; ifconfig eth0 >/tmp/out 2>&1");

            $Try_Again = 1;
            if(-e "/tmp/out") {
                open(DB, "/tmp/out");
                while(<DB>) {
                    if(m/$N{IP}/) {
			$Try_Again = 0;
			last;
                    }
                }
                close(DB);
                unlink("/tmp/out");
            }
	    if($Try_Again) {
		LOG("\n* BAD network parameters. TRY AGAIN.\n");
		sleep(3);
	    }
        }
    }

    $SRC = "/mnt/smbfs";
}


# Mount partimages' network share.
#
if($SRC =~/smbfs$/) {
    #
    # Let's find this directory...
    #
    my $Try_Again = 1;

    while($Try_Again) {
	foreach("Server", "Share", "User", "Passwd", "Directory") {
	    $P{$_} = "";
	}

	my $cmd = 'dialog --inputbox "Enter a valid SMB Server IP '
	    .'(eg. 192.168.0.10)" 8 51 2>/tmp/BLA';
	system($cmd);
	open(DB, "/tmp/BLA");
	while(<DB>) {
	    $P{Server} .= $_;
	}
	close(DB);
	$P{Server} =~s/^\/*//;
	$P{Server} =~s/^\\*//;

	$cmd = 'dialog --inputbox "Enter a valid SMB Share Name '
	    .'(eg. MyShare)" 8 51 2>/tmp/BLA';
	system($cmd);
	open(DB, "/tmp/BLA");
	while(<DB>) {
	    $P{Share} .= $_;
	}
	close(DB);
	$P{Share} =~s/^\/*//;
	$P{Share} =~s/^\\*//;
	$P{Share} =~s/\$/\\\$/g;

	$cmd = 'dialog --inputbox "Enter a valid username '
	    .'(eg. mydomain\johndoe)" 8 51 2>/tmp/BLA';
	system($cmd);
	open(DB, "/tmp/BLA");
	while(<DB>) {
	    $P{User} .= $_;
	}
	close(DB);
	$P{User} =~s/\//\\\\/g;
	$P{User} =~s/\\/\\\\/g;

	$cmd = 'dialog --inputbox "Enter a valid password '
	    .'(eg. secret)" 8 51 2>/tmp/BLA';
	system($cmd);
	open(DB, "/tmp/BLA");
	while(<DB>) {
	    $P{Passwd} .= $_;
	}
	close(DB);
	$P{Passwd} =~s/\\/\//;

	foreach("Server", "Share", "User", "Passwd") {
	    $P{$_} =~s/^\s*//;
	    $P{$_} =~s/\s*$//;
	}

	LOG("* Unmounting /mnt/smbfs\n");
	system("umount /mnt/smbfs >/dev/null 2>&1");
	LOG("* Trying to mount //$P{Server}/$P{Share}\n");
	system("smbmount //$P{Server}/$P{Share} /mnt/smbfs -o"
	       ." username=$P{User},password=$P{Passwd} >/tmp/out 2>&1");

	$Try_Again = 0;
	if(-e "/tmp/out") {
	    open(DB, "/tmp/out");
	    while(<DB>) {
		if(m/failed/i) {
		    # 2e chance
		    my $tmp = `df |grep smbfs |wc -l`;
		    $tmp =~s/\D//g;
		    unless($tmp) {
			$Try_Again = 1;
			LOG("\n* BAD Server, Share, User or Passwd. TRY AGAIN.\n");
			sleep(3);
		    }
		}
	    }
	    close(DB);
	    unlink("/tmp/out");
	}

	if(! $Try_Again) {
	    my $cnt = 0;
	    while($cnt == 0 || ! -d "/mnt/smbfs/$P{Directory}") {
		$P{Directory} = "";
		my $cmd = 'dialog --inputbox "Enter a possible subdirectory '
		    .'containing your data '
		    .'(eg. \mydir\Partimages)" 8 51 2>/tmp/BLA';
		system($cmd);
		open(DB, "/tmp/BLA");
		while(<DB>) {
		    $P{Directory} .= $_;
		}
		close(DB);
		$P{Directory} =~s/^\s*//;
		$P{Directory} =~s/\s*$//;
		$P{Directory} =~s/\\/\//g;
		$P{Directory} =~s/^\/*//;
		++ $cnt;
	    }
	    $SRC = "/mnt/smbfs/$P{Directory}";
	    LOG("* Found SRC: [$SRC]\n");
	}
    }
}


# Get the list of all partimaged Entries.
# Listing the share's directories gives it. And so there's no need
# to modify this script every time a new entry is added...
#
my @Entities = ();

if($SRC =~/smbfs/) {
    opendir(DIR, $SRC);
    my @F = readdir(DIR);
    closedir(DIR);
    foreach(@F) {
        next if m/^\.{1,2}$/;
        next unless(-d "$SRC/$_");
        push(@Entities, $_);
    }
    if($#Entities < 0) {
        LOG("!!! No Entity could be found.\n");
        exit;
    }
}


# Which entry will we install ?
#
my $Entity = '/';

if($SRC =~/smbfs/ || ($SRC =~/cdrom$/ && -e "$SRC/format")) {
    my $cmd = 'dialog --no-cancel --radiolist "Should we install..." 17 50 12 ';
    foreach(@Entities) {
        $cmd .= $_.' "" off ';
    }
    $cmd =~s/ off / on /;     # First radio button ON
    $cmd =~s/ *$//;
    $cmd .= ' 2>/tmp/BLA';
    system($cmd);
    open(DB, "/tmp/BLA");
    while(<DB>)
    {
        $Entity .= $_;
    }
    close(DB);
    unlink("/tmp/BLA");
    $Entity =~s/^\s+//g;
    $Entity =~s/\s+$//g;
}


# Restore partitions.
# Naming convention: files sda1.000 sda1.001 etc. => /dev/sda1.
# File sda contains partitionning information and must be dumped first.
#
if($Entity =~/Partition_and_Format_ANY_Computer/i
   || $Entity =~/Backup_Local_Hard_Disk/i
   || $Entity =~/Blank_Local_Admin_Passwd/i
   || $Entity =~/Create_New_Image/i)
{
    #
    # Find the right HDD device
    #
    my $Dev = '';
    foreach my $d ('hda', 'hdb', 'sda', 'sdb', 'sra', 'srb') {
        my $out = `echo |fdisk /dev/$d 2>&1`;
        $out =~s/^\s*//;
        $out =~s/\s*$//;
        # Either not a partition at all, either is a CDRom = bad cases
        if($out !~/^unable to open/i && $out !~/you will not be able to write/i) {
            $Dev = $d;
            last;
        }
    }

    if($Dev && $Entity =~/Partition_and_Format_ANY_Computer/i) {
        LOG("* Found a HDD device: /dev/$Dev\n");

        # Do the partitions job... argh :=-
        #
	LOG("* Create partitions as specified\n");
	opendir(DIR, "$SRC/$Entity");
	my(@files) = readdir(DIR);
	closedir(DIR);
	foreach my $F (@files) {
	    if($F =~/^.*\.part$/i)
	    {
		my $Dev = $F;
		$Dev =~s/\.part$//i;
		my $CMD_Label = '';

		LOG("  * Found [$F] => partitioning instructions.\n");
		my @fdisk = ('d', 1, 'd', 2, 'd', 3, 'd', 4, 'd', 5, 'd', 6);
		my $cnt = 0;
		open(DB, "$SRC/$Entity/$F");
		while(<DB>) {
		    s/^\s*//;
		    s/\s*$//;
		    s/\s/ /g;
		    while(m/  /) {
			s/  / /g;
		    }
		    next if(m/^\;/);
		    my @fields = split(/ /, $_);
		    next unless($#fields >= 2);
		    my($PNumber, $PSize, $PType, $PLabel, $PBoot) = @fields;

		    push(@fdisk, 'n', 'p', $PNumber, '');
		    if($PSize eq "+") {
			push(@fdisk, '');
		    } else {
			push(@fdisk, "+$PSize");
		    }
		    push(@fdisk, 't');
		    if($cnt > 0) {
			push(@fdisk, $PNumber);
		    }
		    push(@fdisk, $PType);
		    if($PBoot eq "*") {
			push(@fdisk, 'a', $PNumber);
		    }
		    if($PLabel) {
			$CMD_Label .= ";ntfslabel -f /dev/$Dev$PNumber $PLabel";
		    }
		    ++ $cnt;
		}
		close(DB);
		push(@fdisk, 'w');

		my $cmd = 'echo -e "';
		foreach(@fdisk) {
		    $cmd .= $_.'\n';
		}
		$cmd .= '" | fdisk /dev/'.$Dev.' 2>&1';
		LOG("    * [$cmd]\n");
		system($cmd);
		LOG("    * [$CMD_Label]\n");
		system($CMD_Label);

		last;
	    }
        }
        LOG("* Make C: a RAW unformated partition\n");
        system("dd if=/dev/zero of=/dev/$Dev"."1 count=1000 bs=1000");
        #
        # Better not! Decision is easier for windows setup if partition is seen as RAW.
        # print "* Format C: (NTFS)\n";
        # system("mkntfs -L SYSTEM /dev/$Dev"."1");
        #
        LOG("* Format D: (NTFS)\n");
        system("mkntfs -Q -L DATA /dev/$Dev"."2");
        {
            LOG("* Write the partition table again\n");
            my @Do = ('w');
            my $cmd = 'echo -e "';
            foreach(@Do) {
                $cmd .= $_.'\n';
            }
            $cmd .= '" | fdisk /dev/'.$Dev.' 2>&1';
            my $out = `$cmd`;
        }
        system("ntfsfix /dev/$Dev"."2");
        system("ntfslabel -f /dev/$Dev"."2 DATA");
        LOG("* You may safely download a RIS image (unattended setup)!\n");
    }

    elsif($Dev && $Entity =~/Create_New_Image/i) {
	my $New_Image = '';
	while(length($New_Image) < 1) {
	    my $cmd = 'dialog --inputbox "Enter the name of the '
		.'new image :" 8 51 2>/tmp/BLA';
	    system($cmd);
	    open(DB, "/tmp/BLA");
	    while(<DB>) {
		$New_Image .= $_;
	    }
	    close(DB);
	    $New_Image =~s/^\s*//;
	    $New_Image =~s/\s*$//;
	    $New_Image =~s/\s/_/g;
	}
	LOG("* Name of future image: [$New_Image]\n");
	if(-d "$SRC/$New_Image") {
	    LOG("* Renaming old [$SRC/$New_Image]"
		." to [(...).OLD.$$]\n");
	    rename("$SRC/$New_Image",
		   "$SRC/$New_Image.OLD.$$");
	}
	LOG("* Creating dir [$SRC/$New_Image]\n");
	mkdir("$SRC/$New_Image", 0755);
	LOG("* Backuping bios\n");
	system("cmospwd -w $SRC/$New_Image/bios");
	LOG("* Backuping first sectors of $Dev\n");
	system("dd if=/dev/$Dev of=$SRC/$New_Image/$Dev"
	       ." count=20 bs=512");
	LOG("* Listing partitions to be stored\n");
	system("fdisk -l /dev/$Dev >/tmp/BLA");
	my @P = ();
	open(DB, "/tmp/BLA");
	while(<DB>) {
	    if(m/^\/dev\/$Dev/i && ! m/Extended/i) {
		my $tmp = (split(/\//, $_))[2];
		$tmp = (split(/ /, $tmp))[0];
		$tmp =~s/\s//g;
		push(@P, $tmp);
	    }
	}
	close(DB);
	foreach(@P) {
	    LOG("* Checking /dev/$_ for pagefile.sys and hiberfil.sys (to remove)\n");
	    system("mount -t captive-ntfs /dev/$_ /mnt/win");
	    foreach my $file ("pagefile.sys", "hiberfil.sys") {
		if(-e "/mnt/win/$file") {
		    LOG("  * Removing [$file]\n");
		    system("chmod 0666 /mnt/win/$file; rm -f /mnt/win/$file");
		}
	    }
	    system("umount /mnt/win");
	    LOG("* Storing /dev/$_\n");
	    system("partimage -f3 -z1 -b -c -d -o"
		   ." save /dev/$_ $SRC/$New_Image/$_");
	}
	LOG("* Unmounting /mnt/smbfs\n");
	system("umount /mnt/smbfs >/dev/null 2>&1");
    }

    elsif($Dev && $Entity =~/Blank_Local_Admin_Passwd/i) {
	LOG("* Blanking local admin's password!\n");
	LOG("* Mounting /dev/$Dev"."1\n");
	system("umount /mnt/dos >/dev/null 2>&1");
	system("mount -t captive-ntfs /dev/$Dev"."1 /mnt/dos");

	my $SAM = "/mnt/dos";
	opendir(DIR, $SAM);
	my @files = readdir(DIR);
	closedir(DIR);
	foreach(@files) {
	    if(m/^windows$/i) {
		$SAM .= "/$_";
		last;
	    }
	}
	opendir(DIR, $SAM);
	@files = readdir(DIR);
	closedir(DIR);
	foreach(@files) {
	    if(m/^system32$/i) {
		$SAM .= "/$_";
		last;
	    }
	}
	opendir(DIR, $SAM);
	@files = readdir(DIR);
	closedir(DIR);
	foreach(@files) {
	    if(m/^config$/i) {
		$SAM .= "/$_";
		last;
	    }
	}
	opendir(DIR, $SAM);
	@files = readdir(DIR);
	closedir(DIR);
	foreach(@files) {
	    if(m/^SAM$/i) {
		$SAM .= "/$_";
		last;
	    }
	}
	LOG("* Addressing SAM file [$SAM]\n");
	LOG("* Is local admin locked ?\n");
	system("chntpw -l $SAM >/tmp/BLA");
	my $Status = 0;
	open(DB, "/tmp/BLA");
	while(<DB>) {
	    if(m/\<Administrator\>/i && m/locked/i) {
		++ $Status;
		last;
	    }
	}
	close(DB);
	my $Unlock = "";
	if($Status) {
	    $Unlock = "y\n";
	    LOG("* It was locked.\n");
	}
	system("echo -e \"$Unlock*\ny\ny\n\"|chntpw -u Administrator $SAM");
	LOG("* Unmounting /mnt/dos\n");
	system("umount /mnt/dos >/dev/null 2>&1");
    }

    elsif($Dev && $Entity =~/Backup_Local_Hard_Disk/i)
    {
        my %SMB = ();
        my $Try_Again = 1;

        while($Try_Again) {
            foreach("Server", "Share", "User", "Passwd", "Directory") {
                $SMB{$_} = "";
            }

            my $cmd = 'dialog --inputbox "Enter a valid SMB Server IP '
                .'(eg. 192.168.0.10)" 8 51 2>/tmp/BLA';
            system($cmd);
            open(DB, "/tmp/BLA");
            while(<DB>) {
                $SMB{Server} .= $_;
            }
            close(DB);
            $SMB{Server} =~s/^\/*//;
            $SMB{Server} =~s/^\\*//;

            $cmd = 'dialog --inputbox "Enter a valid SMB Share Name '
                .'(eg. myshare)" 8 51 2>/tmp/BLA';
            system($cmd);
            open(DB, "/tmp/BLA");
            while(<DB>) {
                $SMB{Share} .= $_;
            }
            close(DB);
            $SMB{Share} =~s/^\/*//;
            $SMB{Share} =~s/^\\*//;
            $SMB{Share} =~s/\$/\\\$/g;

            $cmd = 'dialog --inputbox "Enter a valid username '
                .'(eg. mydomain\runner)" 8 51 2>/tmp/BLA';
            system($cmd);
            open(DB, "/tmp/BLA");
            while(<DB>) {
                $SMB{User} .= $_;
            }
            close(DB);
            $SMB{User} =~s/\//\\\\/g;
            $SMB{User} =~s/\\/\\\\/g;

            $cmd = 'dialog --inputbox "Enter a valid password '
                .'(eg. runner)" 8 51 2>/tmp/BLA';
            system($cmd);
            open(DB, "/tmp/BLA");
            while(<DB>) {
                $SMB{Passwd} .= $_;
            }
            close(DB);
            $SMB{Passwd} =~s/\\/\//;

            foreach("Server", "Share", "User", "Passwd") {
                $SMB{$_} =~s/^\s*//;
                $SMB{$_} =~s/\s*$//;
            }

            LOG("* Unmounting /mnt/smbfs\n");
            system("umount /mnt/smbfs >/dev/null 2>&1");
            LOG("* Trying to mount //$SMB{Server}/$SMB{Share}\n");
            system("smbmount //$SMB{Server}/$SMB{Share} /mnt/smbfs -o"
                   ." username=$SMB{User},password=$SMB{Passwd} >/tmp/out 2>&1");

            $Try_Again = 0;
            if(-e "/tmp/out") {
                open(DB, "/tmp/out");
                while(<DB>) {
                    if(m/failed/i) {
                        # 2e chance (NAS sends false failures)
                        my $tmp = `df |grep smbfs |wc -l`;
                        $tmp =~s/\D//g;
                        unless($tmp) {
                            $Try_Again = 1;
                            LOG("\n* BAD Server, Share, User or Passwd. TRY AGAIN.\n");
                            sleep(3);
                        }
                    }
                }
                close(DB);
                unlink("/tmp/out");
            }

            if(! $Try_Again) {
                my $cmd = 'dialog --inputbox "Enter a directory where to save data '
                    .'(eg. \MyBackup\MyPC-20060601)" 8 51 2>/tmp/BLA';
                system($cmd);
                open(DB, "/tmp/BLA");
                while(<DB>) {
                    $SMB{Directory} .= $_;
                }
                close(DB);
                $SMB{Directory} =~s/^\s*//;
                $SMB{Directory} =~s/\s*$//;
                $SMB{Directory} =~s/\\/\//g;
                $SMB{Directory} =~s/^\/*//;
            }
        }

        unless(-d "/mnt/smbfs/$SMB{Directory}") {
            LOG("* Making directory //$SMB{Server}/$SMB{Share}/$SMB{Directory}\n");
            system("mkdir -p \"/mnt/smbfs/$SMB{Directory}\"");
        }

        my(@Partitions) = ();
        {
            my @Do = ('p', 'q');
            my $cmd = 'echo -e "';
            foreach(@Do) {
                $cmd .= $_.'\n';
            }
            $cmd .= '" | fdisk /dev/'.$Dev.' 2>&1';
            my $out = `$cmd`;

            my(@lines) = split(/\n/, $out);
            foreach my $L (@lines) {
                $L =~s/^\s*//;
                $L =~s/\s*$//;
                next unless($L =~/^\/dev/i);
                $L =~s/  / /g;
                $L =~s/  / /g;
                $L =~s/  / /g;
                $L =~s/  / /g;
                $L =~s/  / /g;
                my(@fields) = split(/ /, $L);
                next if($fields[$#fields] =~/extended/i);
                push(@Partitions, $fields[0]);
            }
        }

        foreach my $P (@Partitions) {
            my $devname = (split(/\//, $P))[2];
            LOG("\n* Saving partition [$P] to"
                ." [//$SMB{Server}/$SMB{Share}/$SMB{Directory}/$devname]\n");

            LOG("  * Unmounting /mnt/dos\n");
            system("umount /mnt/dos >/dev/null 2>&1");

            LOG("  * Mounting $P on /mnt/dos\n");
            system("mount $P /mnt/dos");

            LOG("  * Tarball-making\n");
            my $cmd = "cd /mnt/dos; tar --exclude=pagefile.sys --exclude="
		."\"System Volume Information\" --exclude=hiberfile.sys"
		." -cvf - *|gzip -1 - |split -b 2000000000 -"
		." \"/mnt/smbfs/$SMB{Directory}/$devname.tar.gz.x\"";
            LOG("    [$cmd]\a\a\n");
            unless(-e "/mnt/smbfs/$SMB{Directory}/$devname.tar.gz.xab") {
                rename("/mnt/smbfs/$SMB{Directory}/$devname.tar.gz.xaa",
                       "/mnt/smbfs/$SMB{Directory}/$devname.tar.gz");
            }
            sleep(3);
            system($cmd);

            LOG("  * Unmounting /mnt/dos\n");
            system("umount /mnt/dos >/dev/null 2>&1");
        }

        LOG("\n* BACKUP has been done.\n");
        LOG("* Unmounting /mnt/smbfs\n");
        system("umount /mnt/smbfs >/dev/null 2>&1");
    }
}
else
{
    my @Label_CMD = ();

    opendir(DIR, "$SRC/$Entity");
    my @F = readdir(DIR);
    closedir(DIR);

    # Resolving symlinks
    #
    LOG("* Resolving possible symlinks\n");
    LOG("  * Before:\n");
    foreach(@F) {
        LOG("    * [$_]\n");
    }
    my @FF = ();
    foreach my $F (@F) {
        next if($F =~/^\.{1,2}/);
        if($F =~/\.symlink/i) {
            my $Link = "";
            open(DB, "$SRC/$Entity/$F");
            while(<DB>) {
                $Link .= $_;
            }
            close(DB);
            $Link =~s/^\s*//;
            $Link =~s/\s*$//;
            $Link =~s/\\/\//g;
            LOG("  * Symlink. Points to [$Link]\n");
            if(-e "$SRC/$Entity/$Link")
            {
                push(@FF, "$SRC/$Entity/$Link");
            }
            else
            {
                LOG("    * [$SRC/$Entity/$Link] can't be found!!!\n");
                sleep(5);
                next;
            }
        } else {
            push(@FF, "$SRC/$Entity/$F");
        }
    }
    LOG("  * After:\n");
    foreach(@FF) {
        LOG("    * [$_]\n");
    }

    # Several possible scenarii to tackle.
    #
    my $Action = "Ghost";
    foreach(@FF) {
        my @fields = split(/\//, $_);
        my $F = $fields[-1];
        if($F =~/^.da\.part$/i) {
            $Action = "Mixed";
            last;
        }
    }

    if($Action eq "Ghost") {
        LOG("* Classical Ghost-like image!\n");
    }
    elsif($Action eq "Mixed") {
        LOG("* Mixed image!\n");
    }

    if($Action eq "Ghost" || $Action eq "Mixed")
    {
        foreach my $FF (@FF) {
            my @fields = split(/\//, $FF);
            my $F = $fields[-1];
            if($F =~/^.da$/) {
                LOG("  * Restore /dev/$F\n");
                my $cmd = "dd if=$FF of=/dev/$F";
                system($cmd);
                $cmd = 'echo -e "w\n" | fdisk /dev/'.$F.' 2>&1';  # Write dd's action
                my $out = `$cmd`;
                LOG("[$out]\n");
                last;
            }
            elsif($F =~/^bios$/i) {
                LOG("  * Restoring CMOS => bios");
                system("echo 2|cmospwd -r $FF");
            }
        }
    }

    # The mixed case. Must:
    # - Partition according to instructions
    # - Apply either partimages, either untarrings (next scope)
    #
    if($Action eq "Mixed")
    {
        foreach my $FF (@FF)
        {
            my @fields = split(/\//, $FF);
            my $F = $fields[-1];
            if($F =~/^.da\.part$/i)
            {
                my $Dev = $F;
                $Dev =~s/\.part$//i;

                LOG("  * Found [$F] => partitioning instructions.\n");
                my @fdisk = ('d', 1, 'd', 2, 'd', 3, 'd', 4, 'd', 5, 'd', 6);
                my $cnt = 0;
                open(DB, $FF);
                while(<DB>) {
                    s/^\s*//;
                    s/\s*$//;
                    s/\s/ /g;
                    while(m/  /) {
                        s/  / /g;
                    }
                    next if(m/^\;/);
                    my @fields = split(/ /, $_);
                    next unless($#fields >= 2);
                    my($PNumber, $PSize, $PType, $PLabel, $PBoot) = @fields;

                    push(@fdisk, 'n', 'p', $PNumber, '');
                    if($PSize eq "+") {
                        push(@fdisk, '');
                    } else {
                        push(@fdisk, "+$PSize");
                    }
                    push(@fdisk, 't');
                    if($cnt > 0) {
                        push(@fdisk, $PNumber);
                    }
                    push(@fdisk, $PType);
                    if($PBoot eq "*") {
                        push(@fdisk, 'a', $PNumber);
                    }

                    if($PLabel) {
                        push(@Label_CMD, "ntfslabel -f /dev/$Dev$PNumber $PLabel");
                    }

                    ++ $cnt;
                }
                close(DB);
                push(@fdisk, 'w');

                my $cmd = 'echo -e "';
                foreach(@fdisk) {
                    $cmd .= $_.'\n';
                }
                $cmd .= '" | fdisk /dev/'.$Dev.' 2>&1';
                LOG("    * [$cmd]\n");
                system($cmd);
            }
        }
    }

    if($Action eq "Ghost" || $Action eq "Mixed")
    {
        foreach my $FF (@FF)
        {
            my @fields = split(/\//, $FF);
            my $F = $fields[-1];
            my $Node = $F;

            unless($F =~/\.000$/ || $F =~/\.zip$/i)
            {
                next;
            }

            LOG("  * Restore [/dev/?? from $F] with [$FF]\n");

            if($FF =~/\.000$/)
            {
                my $Dev = $F;
                $Dev =~s/\.\d{3}$//;
                system("umount /dev/$Dev >/dev/null 2>&1");
                my $cmd = "partimage -f3 -b -c -d -o restore /dev/$Dev $FF";
                LOG("    * [$cmd]\n");
                system($cmd);
            }
            elsif($FF =~/\.zip$/i)
            {
                my $Dev = "";
                {
                    my @f1 = split(/\./, $F);
                    $Dev = $f1[0];
                }
                my $TType = "";
                {
                    my $tmp = $Dev;
                    $tmp =~s/\d+$//;
                    my $out = `fdisk -l /dev/$tmp | grep \"^/dev/$Dev\"`;
                    $out =~s/\+//g;
                    $out =~s/\*//g;
                    $out =~s/^\s*//;
                    $out =~s/\s*$//;
                    while($out =~/  /) {
                        $out =~s/  / /g;
                    }
                    my @fields = split(/ /, $out);
                    if($fields[4] eq "7") {
                        $TType = "-t captive-ntfs";
                    }
                }

                foreach("umount /mnt/dos",
                        "mkntfs -Q -F /dev/$Dev",
                        "ntfsfix /dev/$Dev")
                {
                    LOG("    * [$_]\n");
                    system($_);
                }

                # The tarball might be empty. Then, save time.
                unless(-z $FF) {
                    foreach("mount $TType /dev/$Dev /mnt/dos",
                            "cd /mnt/dos; unzip $FF; sleep 2",
                            "cd /; umount /mnt/dos; sleep 2")
                    {
                        LOG("    * [$_]\n");
                        system($_);
                    }
                }
            }
            else
            {
                LOG("    * Dunno what to do with [$FF]. Probably safe.\n");
            }
        }
    }

    if($Action eq "Mixed")
    {
        foreach(@Label_CMD) {
            LOG("    * [$_]\n");
            system($_);
        }
    }
}


# Unmount the stuff.
#
system("umount $SRC >/dev/null 2>&1");


# Reboot.
#
LOG("* Reboot within 10s !!\a\a\a\n\n");
if($SRC =~/cdrom/i) {
    LOG("* Hey! Don't forget thy DVD!\a\a\a\n\n");
    system("eject /mnt/cdrom >/dev/null 2>&1");
}
sleep(10);
system("shutdown -r now");



sub LOG
{
    my $Say = shift;
    print $Say;
    open(LOG, ">>/tmp/x.log");
    print LOG $Say;
    close(LOG);
}
