]> git.proxmox.com Git - pve-zsync.git/blobdiff - pve-zsync
Avoid 'no such file' error when no state exists.
[pve-zsync.git] / pve-zsync
index 47e7b590f5a63e0ea7761fb80b7b2b853fa33387..9de01d2de0cf34b2879009bdbd4a8f87b81db9c9 100644 (file)
--- a/pve-zsync
+++ b/pve-zsync
@@ -1,20 +1,26 @@
 #!/usr/bin/perl
 
 #!/usr/bin/perl
 
-my $PROGNAME = "pve-zsync";
-my $CONFIG_PATH = '/var/lib/'.$PROGNAME.'/';
-my $CONFIG = "$PROGNAME.cfg";
-my $CRONJOBS = '/etc/cron.d/'.$PROGNAME;
-my $VMCONFIG = '/var/lib/'.$PROGNAME.'/';
-my $PATH = "/usr/sbin/";
-my $QEMU_CONF = '/etc/pve/local/qemu-server/';
-my $DEBUG = 0;
-
 use strict;
 use warnings;
 use Data::Dumper qw(Dumper);
 use Fcntl qw(:flock SEEK_END);
 use strict;
 use warnings;
 use Data::Dumper qw(Dumper);
 use Fcntl qw(:flock SEEK_END);
-use Getopt::Long;
+use Getopt::Long qw(GetOptionsFromArray);
+use File::Copy qw(move);
+use File::Path qw(make_path);
 use Switch;
 use Switch;
+use JSON;
+use IO::File;
+
+my $PROGNAME = "pve-zsync";
+my $CONFIG_PATH = "/var/lib/${PROGNAME}/";
+my $STATE = "${CONFIG_PATH}sync_state";
+my $CRONJOBS = "/etc/cron.d/$PROGNAME";
+my $PATH = "/usr/sbin/";
+my $QEMU_CONF = "/etc/pve/local/qemu-server/";
+my $LOCKFILE = "$CONFIG_PATH${PROGNAME}.lock";
+my $PROG_PATH = "$PATH${PROGNAME}";
+my $INTERVAL = 15;
+my $DEBUG = 0;
 
 check_bin ('cstream');
 check_bin ('zfs');
 
 check_bin ('cstream');
 check_bin ('zfs');
@@ -31,14 +37,14 @@ sub check_bin {
        }
     }
 
        }
     }
 
-    warn "unable to find command '$bin'\n";
+    die "unable to find command '$bin'\n";
 }
 
 }
 
-sub cut_to_width {
-    my ($text, $max) = @_;
+sub cut_target_width {
+    my ($target, $max) = @_;
 
 
-    return  $text if (length($text) <= $max);
-    my @spl = split('/', $text);
+    return  $target if (length($target) <= $max);
+    my @spl = split('/', $target);
 
     my $count = length($spl[@spl-1]);
     return "..\/".substr($spl[@spl-1],($count-$max)+3 ,$count) if $count > $max;
 
     my $count = length($spl[@spl-1]);
     return "..\/".substr($spl[@spl-1],($count-$max)+3 ,$count) if $count > $max;
@@ -46,232 +52,352 @@ sub cut_to_width {
     $count +=  length($spl[0]) if @spl > 1;
     return substr($spl[0], 0, $max-4-length($spl[@spl-1]))."\/..\/".$spl[@spl-1] if $count > $max;
 
     $count +=  length($spl[0]) if @spl > 1;
     return substr($spl[0], 0, $max-4-length($spl[@spl-1]))."\/..\/".$spl[@spl-1] if $count > $max;
 
-    my $rest = 1 ;
+    my $rest = 1;
     $rest = $max-$count if ($max-$count > 0);
 
     $rest = $max-$count if ($max-$count > 0);
 
-    return "$spl[0]".substr($text, length($spl[0]), $rest)."..\/".$spl[@spl-1];
+    return "$spl[0]".substr($target, length($spl[0]), $rest)."..\/".$spl[@spl-1];
 }
 
 sub lock {
     my ($fh) = @_;
 }
 
 sub lock {
     my ($fh) = @_;
-    flock($fh, LOCK_EX) or die "Cannot lock config - $!\n";
-
-    seek($fh, 0, SEEK_END) or die "Cannot seek - $!\n";
+    flock($fh, LOCK_EX) || die "Can't lock config - $!\n";
 }
 
 sub unlock {
     my ($fh) = @_;
 }
 
 sub unlock {
     my ($fh) = @_;
-    flock($fh, LOCK_UN) or die "Cannot unlock config- $!\n";
+    flock($fh, LOCK_UN) || die "Can't unlock config- $!\n";
 }
 
 }
 
-sub check_config {
-    my ($source, $name, $cfg) = @_;
+sub get_status {
+    my ($source, $name, $status) = @_;
 
 
-    if ($source->{vmid}  && $cfg->{$source->{vmid}}->{$name}->{locked}){
-       return "active" if $cfg->{$source->{vmid}}->{$name}->{locked} eq 'yes';
-       return "exist" if $cfg->{$source->{vmid}}->{$name}->{locked} eq 'no';
-    } elsif ($cfg->{$source->{abs_path}}->{$name}->{locked}) {
-       return "active" if $cfg->{$source->{abs_path}}->{$name}->{locked} eq 'yes';
-       return "exist" if $cfg->{$source->{abs_path}}->{$name}->{locked} eq 'no';
+    if ($status->{$source->{all}}->{$name}->{status}) {
+       return $status;
     }
 
     return undef;
 }
 
     }
 
     return undef;
 }
 
-
-sub check_pool_exsits {
-    my ($pool, $ip) = @_;
+sub check_pool_exists {
+    my ($target) = @_;
 
     my $cmd = '';
 
     my $cmd = '';
-    $cmd = "ssh root\@$ip " if $ip;
-    $cmd .= "zfs list $pool -H";
+    $cmd = "ssh root\@$target->{ip} " if $target->{ip};
+    $cmd .= "zfs list $target->{all} -H";
     eval {
        run_cmd($cmd);
     };
 
     eval {
        run_cmd($cmd);
     };
 
-    if($@){
+    if ($@) {
        return 1;
     }
     return undef;
 }
 
        return 1;
     }
     return undef;
 }
 
-sub write_to_config {
-    my ($cfg) = @_;
+sub parse_target {
+    my ($text) = @_;
 
 
-    open(my $fh, ">", "$CONFIG_PATH$CONFIG")
-       or die "cannot open >$CONFIG_PATH$CONFIG: $!\n";
+    my $errstr = "$text : is not a valid input! Use [IP:]<VMID> or [IP:]<ZFSPool>[/Path]";
+    my $target = {};
 
 
-    my $text = decode_config($cfg);
+    $text =~ m/^((\d+.\d+.\d+.\d+):)?(.*)$/;
 
 
-    print($fh $text);
+    $target->{all} = $3;
 
 
-    close($fh);
+    if ($2) {
+       $target->{ip} = $2;
+    }
+    my @parts = split('/', $3);
+
+    die "$text $errstr\n" if !($target->{pool} = shift(@parts));
+    die "$text $errstr\n" if $target->{pool} =~ /^(\d+.\d+.\d+.\d+)$/;
+
+    if ($target->{pool} =~ m/^\d+$/) {
+       $target->{vmid} = $target->{pool};
+       delete $target->{pool};
+    }
+
+    return $target if (@parts == 0);
+    $target->{last_part} = pop(@parts);
+
+    if ($target->{ip}) {
+       pop(@parts);
+    }
+    if (@parts > 0) {
+       $target->{path} = join('/', @parts);
+    }
+
+    return $target;
 }
 
 }
 
-sub read_from_config {
+sub read_cron {
 
 
-    unless(-e "$CONFIG_PATH$CONFIG") {
+    #This is for the first use to init file;
+    if (!-e $CRONJOBS) {
+       my $new_fh = IO::File->new("> $CRONJOBS");
+       die "Could not create $CRONJOBS: $!\n" if !$new_fh;
+       close($new_fh);
        return undef;
     }
 
        return undef;
     }
 
-    open(my $fh, "<", "$CONFIG_PATH$CONFIG")
-       or die "cannot open > $CONFIG_PATH$CONFIG: $!\n";
+    my $fh = IO::File->new("< $CRONJOBS");
+    die "Could not open file $CRONJOBS: $!\n" if !$fh;
 
 
-    $/ = undef;
+    my @text = <$fh>;
 
 
-    my $text = <$fh>;
+    close($fh);
 
 
-    unlock($fh);
+    return encode_cron(@text);
+}
 
 
-    close($fh);
+sub parse_argv {
+    my (@arg) = @_;
+
+    my $param = {};
+    $param->{dest} = undef;
+    $param->{source} = undef;
+    $param->{verbose} = undef;
+    $param->{limit} = undef;
+    $param->{maxsnap} = undef;
+    $param->{name} = undef;
+    $param->{skip} = undef;
+    $param->{method} = undef;
+
+    my ($ret, $ar) = GetOptionsFromArray(\@arg,
+                                          'dest=s' => \$param->{dest},
+                                          'source=s' => \$param->{source},
+                                          'verbose' => \$param->{verbose},
+                                          'limit=i' => \$param->{limit},
+                                          'maxsnap=i' => \$param->{maxsnap},
+                                          'name=s' => \$param->{name},
+                                          'skip' => \$param->{skip},
+                                          'method=s' => \$param->{method});
+
+    if ($ret == 0) {
+       die "can't parse options\n";
+    }
 
 
-    my $cfg = encode_config($text);
+    $param->{name} = "default" if !$param->{name};
+    $param->{maxsnap} = 1 if !$param->{maxsnap};
+    $param->{method} = "ssh" if !$param->{method};
 
 
-    return $cfg;
+    return $param;
 }
 
 }
 
-sub decode_config {
-    my ($cfg) = @_;
-    my $raw = '';
-    foreach my $source (sort keys%{$cfg}){
-       foreach my $sync_name (sort keys%{$cfg->{$source}}){
-           $raw .= "$source: $sync_name\n";
-               foreach my $parameter (sort keys%{$cfg->{$source}->{$sync_name}}){
-                   $raw .= "\t$parameter: $cfg->{$source}->{$sync_name}->{$parameter}\n";
-               }
-       }
+sub add_state_to_job {
+    my ($job) = @_;
+
+    my $states = read_state();
+    my $state = $states->{$job->{source}}->{$job->{name}};
+
+    $job->{state} = $state->{state};
+    $job->{lsync} = $state->{lsync};
+
+    for (my $i = 0; $state->{"snap$i"}; $i++) {
+       $job->{"snap$i"} = $state->{"snap$i"};
     }
     }
-    return $raw;
+
+    return $job;
 }
 
 }
 
-sub encode_config {
-    my ($raw) = @_;
+sub encode_cron {
+    my (@text) = @_;
+
     my $cfg = {};
     my $cfg = {};
-    my $source;
-    my $check = 0;
-    my $sync_name;
 
 
-    while ($raw && $raw =~ s/^(.*?)(\n|$)//) {
-       my $line = $1;
+    while (my $line = shift(@text)) {
 
 
-       next if $line =~ m/^\#/;
-       next if $line =~ m/^\s*$/;
-
-       if ($line =~ m/^(\t| )(\w+): (.+)/){
-           my $par = $2;
-           my $value = $3;
-
-           if ($par eq 'source_pool') {
-               $cfg->{$source}->{$sync_name}->{$par} = $value;
-               die "error in Config: SourcePool value doubled\n" if ($check & 1);
-               $check += 1;
-           } elsif ($par eq 'source_ip') {
-               $cfg->{$source}->{$sync_name}->{$par} = $value;
-               die "error in Config: SourceIP value doubled\n" if ($check & 2);
-               $check += 2;
-           } elsif ($par eq 'locked') {
-               $cfg->{$source}->{$sync_name}->{$par} = $value;
-               die "error in Config: Locked value doubled\n" if ($check & 4);
-               $check += 4;
-           } elsif ($par eq 'method') {
-               $cfg -> {$source}->{$sync_name}->{$par} = $value;
-               die "error in Config: Method value doubled\n" if ($check & 8);
-               $check += 8;
-           } elsif ($par eq 'interval') {
-               $cfg -> {$source}->{$sync_name}->{$par} = $value;
-               die "error in Config: Iterval value doubled\n" if ($check & 16);
-               $check += 16;
-           } elsif ($par eq 'limit') {
-               $cfg -> {$source}->{$sync_name}->{$par} = $value;
-               die "error in Config: Limit value doubled\n" if ($check & 32);
-               $check += 32;
-           } elsif ($par eq 'dest_pool') {
-               $cfg -> {$source}->{$sync_name}->{$par} = $value;
-               die "error in Config: DestPool value doubled\n" if ($check & 64);
-               $check += 64;
-           } elsif ($par eq 'dest_ip') {
-               $cfg -> {$source}->{$sync_name}->{$par} = $value;
-               die "error in Config: DestIp value doubled\n" if ($check & 128);
-               $check += 128;
-           } elsif ($par eq 'dest_path') {
-               $cfg -> {$source}->{$sync_name}->{$par} = $value;
-               die "error in Config: DestPath value doubled\n" if ($check & 256);
-               $check += 256;
-           } elsif ($par eq 'source_path') {
-               $cfg -> {$source}->{$sync_name}->{$par} = $value;
-               die "error in Config: SourcePath value doubled\n" if ($check & 512);
-               $check += 512;
-           } elsif ($par eq 'vmid') {
-               $cfg -> {$source}->{$sync_name}->{$par} = $value;
-               die "error in Config: Vmid value doubled\n" if ($check & 1024);
-               $check += 1024;
-           } elsif ($par =~ 'lsync') {
-               $cfg->{$source}->{$sync_name}->{$par} = $value;
-               die "error in Config: lsync value doubled\n" if ($check & 2048);
-               $check += 2048;
-           } elsif ($par =~ 'maxsnap') {
-               $cfg->{$source}->{$sync_name}->{$par} = $value;
-               die "error in Config: maxsnap value doubled\n" if ($check & 4096);
-               $check += 4096;
-           } else {
-               die "error in Config\n";
-           }
-       } elsif ($line =~ m/^((\d+.\d+.\d+.\d+):)?([\w\-\_\/]+): (.+){0,1}/){
-           $source = $3;
-           $sync_name = $4 ? $4 : 'default' ;
-           $cfg->{$source}->{$sync_name} = undef;
-           $cfg->{$source}->{$sync_name}->{source_ip} = $2 if $2;
-           $check = 0;
+       my @arg = split('\s', $line);
+       my $param = parse_argv(@arg);
+
+       if ($param->{source} && $param->{dest}) {
+           $cfg->{$param->{source}}->{$param->{name}}->{dest} = $param->{dest};
+           $cfg->{$param->{source}}->{$param->{name}}->{verbose} = $param->{verbose};
+           $cfg->{$param->{source}}->{$param->{name}}->{limit} = $param->{limit};
+           $cfg->{$param->{source}}->{$param->{name}}->{maxsnap} = $param->{maxsnap};
+           $cfg->{$param->{source}}->{$param->{name}}->{skip} = $param->{skip};
+           $cfg->{$param->{source}}->{$param->{name}}->{method} = $param->{method};
        }
     }
        }
     }
+
     return $cfg;
 }
 
     return $cfg;
 }
 
-sub parse_target {
-    my ($text) = @_;
+sub param_to_job {
+    my ($param) = @_;
+
+    my $job = {};
+
+    my $source = parse_target($param->{source});
+    my $dest = parse_target($param->{dest}) if $param->{dest};
+
+    $job->{name} = !$param->{name} ? "default" : $param->{name};
+    $job->{dest} = $param->{dest} if $param->{dest};
+    $job->{method} = "local" if !$dest->{ip} && !$source->{ip};
+    $job->{method} = "ssh" if !$job->{method};
+    $job->{limit} = $param->{limit};
+    $job->{maxsnap} = $param->{maxsnap} if $param->{maxsnap};
+    $job->{source} = $param->{source};
 
 
-    if ($text =~ m/^((\d+.\d+.\d+.\d+):)?((\w+)\/?)([\w\/\-\_]*)?$/) {
+    return $job;
+}
+
+sub read_state {
 
 
-       die "Input not valid\n" if !$3;
-       my $tmp = $3;
-       my $target = {};
+    if (!-e $STATE) {
+       make_path $CONFIG_PATH;
+       my $new_fh = IO::File->new("> $STATE");
+       die "Could not create $STATE: $!\n" if !$new_fh;
+       print $new_fh "{}";
+       close($new_fh);
+       return undef;
+    }
+
+    my $fh = IO::File->new("< $STATE");
+    die "Could not open file $STATE: $!\n" if !$fh;
+
+    my $text = <$fh>;
+    my $states = decode_json($text);
 
 
-       if ($2) {
-           $target->{ip} = $2 ;
+    close($fh);
+
+    return $states;
+}
+
+sub update_state {
+    my ($job) = @_;
+    my $text;
+    my $in_fh;
+
+    eval {
+
+       $in_fh = IO::File->new("< $STATE");
+       die "Could not open file $STATE: $!\n" if !$in_fh;
+       lock($in_fh);
+       $text = <$in_fh>;
+    };
+
+    my $out_fh = IO::File->new("> $STATE.new");
+    die "Could not open file ${STATE}.new: $!\n" if !$out_fh;
+
+    my $states = {};
+    my $state = {};
+    if ($text){
+       $states = decode_json($text);
+       $state = $states->{$job->{source}}->{$job->{name}};
+    }
+
+    if ($job->{state} ne "del") {
+       $state->{state} = $job->{state};
+       $state->{lsync} = $job->{lsync};
+
+       for (my $i = 0; $job->{"snap$i"} ; $i++) {
+           $state->{"snap$i"} = $job->{"snap$i"};
        }
        }
+       $states->{$job->{source}}->{$job->{name}} = $state;
+    } else {
 
 
-       if ($tmp =~ m/^(\d\d\d+)$/){
-           $target->{vmid} = $tmp;
+       delete $states->{$job->{source}}->{$job->{name}};
+       delete $states->{$job->{source}} if !keys %{$states->{$job->{source}}};
+    }
+
+    $text = encode_json($states);
+    print $out_fh $text;
+
+    close($out_fh);
+    move("$STATE.new", $STATE);
+    eval {
+       close($in_fh);
+    };
+
+    return $states;
+}
+
+sub update_cron {
+    my ($job) = @_;
+
+    my $updated;
+    my $has_header;
+    my $line_no = 0;
+    my $text = "";
+    my $header = "SHELL=/bin/sh\n";
+    $header .= "PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\n\n";
+
+    my $fh = IO::File->new("< $CRONJOBS");
+    die "Could not open file $CRONJOBS: $!\n" if !$fh;
+    lock($fh);
+
+    my @test = <$fh>;
+
+    while (my $line = shift(@test)) {
+       chomp($line);
+       if ($line =~ m/source $job->{source} .*name $job->{name} /) {
+           $updated = 1;
+           next if $job->{state} eq "del";
+           $text .= format_job($job, $line);
        } else {
        } else {
-           $target->{pool} = $4;
-           my $abs_path = $4;
-           if ($5) {
-               $target->{path} = "\/$5";
-               $abs_path .= "\/$5";
+           if (($line_no < 3) && ($line =~ /^(PATH|SHELL)/ )) {
+               $has_header = 1;
            }
            }
-           $target->{abs_path} = $abs_path;
+           $text .= "$line\n";
        }
        }
+       $line_no++;
+    }
+
+    if (!$has_header) {
+       $text = "$header$text";
+    }
 
 
-       return $target;
+    if (!$updated) {
+        $text .= format_job($job);
     }
     }
-    die "Input not valid\n";
+    my $new_fh = IO::File->new("> ${CRONJOBS}.new");
+    die "Could not open file ${CRONJOBS}.new: $!\n" if !$new_fh;
+
+    die "can't write to $CRONJOBS.new\n" if !print($new_fh $text);
+    close ($new_fh);
+
+    die "can't move $CRONJOBS.new: $!\n" if !move("${CRONJOBS}.new", "$CRONJOBS");
+    close ($fh);
+}
+
+sub format_job {
+    my ($job, $line) = @_;
+    my $text = "";
+
+    if ($job->{state} eq "stopped") {
+       $text = "#";
+    }
+    if ($line) {
+       $line =~ /^#*(.+) root/;
+       $text .= $1;
+    } else {
+       $text .= "*/$INTERVAL * * * *";
+    }
+    $text .= " root";
+    $text .= " $PROGNAME sync --source $job->{source} --dest $job->{dest}";
+    $text .= " --name $job->{name} --maxsnap $job->{maxsnap}";
+    $text .= " --method $job->{method}";
+    $text .= " --verbose" if $job->{verbose};
+    $text .= "\n";
+
+    return $text;
 }
 
 sub list {
 
 }
 
 sub list {
 
-    my $cfg = read_from_config("$CONFIG_PATH$CONFIG");
-
-    my $list = sprintf("%-25s%-15s%-7s%-20s%-10s%-5s\n" , "SOURCE", "NAME", "ACTIVE", "LAST SYNC", "INTERVAL", "TYPE");
-    
-    foreach my $source (sort keys%{$cfg}){
-       foreach my $sync_name (sort keys%{$cfg->{$source}}){
-           my $source_name = $source;
-           $source_name = $cfg->{$source}->{$sync_name}->{source_ip}.":".$source if $cfg->{$source}->{$sync_name}->{source_ip};
-           $list .= sprintf("%-25s%-15s", cut_to_width($source_name,25), cut_to_width($sync_name,15));
-           $list .= sprintf("%-7s",$cfg->{$source}->{$sync_name}->{locked});
-           $list .= sprintf("%-20s",$cfg->{$source}->{$sync_name}->{lsync});
-           $list .= sprintf("%-10s",$cfg->{$source}->{$sync_name}->{interval});
-           $list .= sprintf("%-5s\n",$cfg->{$source}->{$sync_name}->{method});
+    my $cfg = read_cron();
+
+    my $list = sprintf("%-25s%-15s%-7s%-20s%-5s\n" , "SOURCE", "NAME", "STATE", "LAST SYNC", "TYPE");
+
+    my $states = read_state();
+    foreach my $source (sort keys%{$cfg}) {
+       foreach my $name (sort keys%{$cfg->{$source}}) {
+           $list .= sprintf("%-25s", cut_target_width($source, 25));
+           $list .= sprintf("%-15s", cut_target_width($name, 15));
+           $list .= sprintf("%-7s", $states->{$source}->{$name}->{state});
+           $list .= sprintf("%-20s",$states->{$source}->{$name}->{lsync});
+           $list .= sprintf("%-5s\n",$cfg->{$source}->{$name}->{method});
        }
     }
 
        }
     }
 
@@ -294,186 +420,148 @@ sub vm_exists {
 sub init {
     my ($param) = @_;
 
 sub init {
     my ($param) = @_;
 
-    my $cfg = read_from_config;
+    my $cfg = read_cron();
 
 
-    my $vm = {};
+    my $job = param_to_job($param);
 
 
-    my $name =  $param->{name} ? $param->{name} : "default";
-    my $interval = $param->{interval} ? $param->{interval} : 15;
+    $job->{state} = "ok";
+    $job->{lsync} = 0;
 
     my $source = parse_target($param->{source});
     my $dest = parse_target($param->{dest});
 
 
     my $source = parse_target($param->{source});
     my $dest = parse_target($param->{dest});
 
-    $vm->{$name}->{dest_pool} = $dest->{pool};
-    $vm->{$name}->{dest_ip} = $dest->{ip} if $dest->{ip};
-    $vm->{$name}->{dest_path} = $dest->{path} if $dest->{path};
-
-    $param->{method} = "local" if !$dest->{ip} && !$source->{ip};
-    $vm->{$name}->{locked} = "no";
-    $vm->{$name}->{interval} = $interval;
-    $vm->{$name}->{method} = $param->{method} ? $param->{method} : "ssh";
-    $vm->{$name}->{limit} = $param->{limit} if $param->{limit};
-    $vm->{$name}->{maxsnap} = $param->{maxsnap} if $param->{maxsnap};
-
-    if ( my $ip =  $vm->{$name}->{dest_ip} ) {
+    if (my $ip =  $dest->{ip}) {
        run_cmd("ssh-copy-id -i /root/.ssh/id_rsa.pub root\@$ip");
     }
 
        run_cmd("ssh-copy-id -i /root/.ssh/id_rsa.pub root\@$ip");
     }
 
-    if ( my $ip =  $source->{ip} ) {
+    if (my $ip =  $source->{ip}) {
        run_cmd("ssh-copy-id -i /root/.ssh/id_rsa.pub root\@$ip");
     }
 
        run_cmd("ssh-copy-id -i /root/.ssh/id_rsa.pub root\@$ip");
     }
 
-    die "Pool $dest->{abs_path} does not exists\n" if check_pool_exsits($dest->{abs_path}, $dest->{ip});
+    die "Pool $dest->{all} does not exists\n" if check_pool_exists($dest);
 
 
-    my $check = check_pool_exsits($source->{abs_path}, $source->{ip}) if !$source->{vmid} && $source->{abs_path};
+    my $check = check_pool_exists($source->{path}, $source->{ip}) if !$source->{vmid} && $source->{path};
 
 
-    die "Pool $source->{abs_path} does not exists\n" if undef($check);
+    die "Pool $source->{path} does not exists\n" if undef($check);
 
 
-    my $add_job = sub {
-       my ($vm, $name) = @_;
-       my $source = "";
+    die "VM $source->{vmid} doesn't exist\n" if $param->{vmid} && !vm_exists($source);
 
 
-       if ($vm->{$name}->{vmid}) {
-           $source = "$vm->{$name}->{source_ip}:" if $vm->{$name}->{source_ip};
-           $source .= $vm->{$name}->{vmid};
-       } else {
-           $source = $vm->{$name}->{source_pool};
-           $source .= $vm->{$name}->{source_path} if $vm->{$name}->{source_path};
-       }
-       die "Config already exists\n" if $cfg->{$source}->{$name};
-
-       cron_add($vm);
+    die "Config already exists\n" if $cfg->{$job->{source}}->{$job->{name}};
 
 
-       $cfg->{$source}->{$name} = $vm->{$name};
+    update_cron($job);
+    update_state($job);
 
 
-       write_to_config($cfg);
+    eval {
+       sync($param) if !$param->{skip};
     };
     };
-
-    if ($source->{vmid}) {
-       die "VM $source->{vmid} doesn't exist\n" if !vm_exists($source);
-       my $disks = get_disks($source);
-       $vm->{$name}->{vmid} = $source->{vmid};
-       $vm->{$name}->{lsync} = 0;
-       $vm->{$name}->{source_ip} = $source->{ip} if $source->{ip};
-
-       &$add_job($vm, $name);
-
-    } else {
-       $vm->{$name}->{source_pool} = $source->{pool};
-        $vm->{$name}->{source_ip} = $source->{ip} if $source->{ip};
-       $vm->{$name}->{source_path} = $source->{path} if $source->{path};
-       $vm->{$name}->{lsync} = 0;
-
-       &$add_job($vm, $name);
-    }
-
-    eval {sync($param) if !$param->{skip};};
     if(my $err = $@) {
     if(my $err = $@) {
-       destroy($param);
+       destroy_job($param);
        print $err;
     }
 }
 
        print $err;
     }
 }
 
-sub destroy {
+sub get_job {
     my ($param) = @_;
 
     my ($param) = @_;
 
-    my $cfg = read_from_config("$CONFIG_PATH$CONFIG");
-    my $name =  $param->{name} ? $param->{name} : "default";
-
-    my $source = parse_target($param->{source});
-
-    my $delete_cron = sub {
-       my ($path, $name, $cfg) = @_;
-
-       die "Source does not exist!\n" unless $cfg->{$path} ;
+    my $cfg = read_cron();
 
 
-       die "Sync Name does not exist!\n" unless $cfg->{$path}->{$name};
-
-       delete $cfg->{$path}->{$name};
-
-       delete $cfg->{$path} if keys%{$cfg->{$path}} == 0;
-
-       write_to_config($cfg);
-
-       cron_del($path, $name);
-    };
-
-
-    if ($source->{vmid}) {
-       my $path = $source->{vmid};
+    if (!$cfg->{$param->{source}}->{$param->{name}}) {
+       die "Job  with source $param->{source} and name $param->{name} does not exist\n" ;
+    }
+    my $job = $cfg->{$param->{source}}->{$param->{name}};
+    $job->{name} = $param->{name};
+    $job->{source} = $param->{source};
+    $job = add_state_to_job($job);
 
 
-        &$delete_cron($path, $name, $cfg)
+    return $job;
+}
 
 
-    } else {
+sub destroy_job {
+    my ($param) = @_;
 
 
-       my $path = $source->{pool};
-       $path .= $source->{path} if $source->{path};
+    my $job = get_job($param);
+    $job->{state} = "del";
 
 
-       &$delete_cron($path, $name, $cfg);
-    }
+    update_cron($job);
+    update_state($job);
 }
 
 sub sync {
     my ($param) = @_;
 
 }
 
 sub sync {
     my ($param) = @_;
 
-    my $cfg = read_from_config("$CONFIG_PATH$CONFIG");
+    my $lock_fh = IO::File->new("> $LOCKFILE");
+    die "Can't open Lock File: $LOCKFILE $!\n" if !$lock_fh;
+    lock($lock_fh);
 
 
-    my $name =  $param->{name} ? $param->{name} : "default";
-    my $max_snap = $param->{maxsnap} ? $param->{maxsnap} : 1;
-    my $method = $param->{method} ? $param->{method} : "ssh";
+    my $date = get_date();
+    my $job;
+    eval {
+       $job = get_job($param);
+    };
+
+    if ($job && $job->{state} eq "syncing") {
+       die "Job --source $param->{source} --name $param->{name} is syncing at the moment";
+    }
 
     my $dest = parse_target($param->{dest});
     my $source = parse_target($param->{source});
 
     my $sync_path = sub {
 
     my $dest = parse_target($param->{dest});
     my $source = parse_target($param->{source});
 
     my $sync_path = sub {
-       my ($source, $name, $cfg, $max_snap, $dest, $method) = @_;
+       my ($source, $dest, $job, $param, $date) = @_;
 
 
-       ($source->{old_snap},$source->{last_snap}) = snapshot_get($source, $dest, $max_snap, $name);
+       ($source->{old_snap},$source->{last_snap}) = snapshot_get($source, $dest, $param->{maxsnap}, $param->{name});
 
 
-       my $job_status = check_config($source, $name, $cfg) if $cfg;
-       die "VM syncing at the moment!\n" if ($job_status && $job_status eq "active");
-
-       if ($job_status && $job_status eq "exist") {
-           my $conf_name = $source->{abs_path};
-           $conf_name = $source->{vmid} if $source->{vmid};
-           $cfg->{$conf_name}->{$name}->{locked} = "yes";
-           write_to_config($cfg);
-       }
+       snapshot_add($source, $dest, $param->{name}, $date);
 
 
-       my $date = snapshot_add($source, $dest, $name);
+       send_image($source, $dest, $param);
 
 
-       send_image($source, $dest, $method, $param->{verbose}, $param->{limit});
+       snapshot_destroy($source, $dest, $param->{method}, $source->{old_snap}) if ($source->{destroy} && $source->{old_snap});
 
 
-       snapshot_destroy($source, $dest, $method, $source->{old_snap}) if ($source->{destroy} && $source->{old_snap});
+    };
 
 
+    if ($job) {
+       $job->{state} = "syncing";
+       update_state($job);
+    }
 
 
-       if ($job_status && $job_status eq "exist") {
-           my $conf_name = $source->{abs_path};
-           $conf_name = $source->{vmid} if $source->{vmid};
-           $cfg->{$conf_name}->{$name}->{locked} = "no";
-           $cfg->{$conf_name}->{$name}->{lsync} = $date;
-           write_to_config($cfg);
+    eval{
+       if ($source->{vmid}) {
+           die "VM $source->{vmid} doesn't exist\n" if !vm_exists($source);
+           my $disks = get_disks($source);
+
+           foreach my $disk (sort keys %{$disks}) {
+               $source->{all} = $disks->{$disk}->{all};
+               $source->{pool} = $disks->{$disk}->{pool};
+               $source->{path} = $disks->{$disk}->{path} if $disks->{$disk}->{path};
+               $source->{last_part} = $disks->{$disk}->{last_part};
+               &$sync_path($source, $dest, $job, $param, $date);
+           }
+           if ($param->{method} eq "ssh") {
+               send_config($source, $dest,'ssh');
+           }
+       } else {
+           &$sync_path($source, $dest, $job, $param, $date);
        }
     };
        }
     };
-
-    $param->{method}  = "ssh" if  !$param->{method};
-
-    if ($source->{vmid}) {
-        die "VM $source->{vmid} doesn't exist\n" if !vm_exists($source);
-       my $disks = get_disks($source);
-
-        foreach my $disk (keys %{$disks}) {
-           $source->{abs_path} = $disks->{$disk}->{pool};
-           $source->{abs_path} .= "\/$disks->{$disk}->{path}" if $disks->{$disk}->{path};
-
-           $source->{pool} = $disks->{$disk}->{pool};
-           $source->{path} = "\/$disks->{$disk}->{path}";
-
-           &$sync_path($source, $name, $cfg, $max_snap, $dest, $method);
+    if(my $err = $@) {
+       if ($job) {
+           $job->{state} = "error";
+           update_state($job);
+           unlock($lock_fh);
+           close($lock_fh);
+           print "Job --source $param->{source} --name $param->{name} got an ERROR!!!\nERROR Message:\n";
        }
        }
-    } else {
-       &$sync_path($source, $name, $cfg, $max_snap, $dest, $method);
+       die "$err\n";
     }
     }
+
+    if ($job) {
+       $job->{state} = "ok";
+       $job->{lsync} = $date;
+       update_state($job);
+    }
+
+    unlock($lock_fh);
+    close($lock_fh);
 }
 
 sub snapshot_get{
 }
 
 sub snapshot_get{
@@ -481,106 +569,88 @@ sub snapshot_get{
 
     my $cmd = "zfs list -r -t snapshot -Ho name, -S creation ";
 
 
     my $cmd = "zfs list -r -t snapshot -Ho name, -S creation ";
 
-    $cmd .= $source->{abs_path};
+    $cmd .= $source->{all};
     $cmd = "ssh root\@$source->{ip} ".$cmd if $source->{ip};
 
     my $raw = run_cmd($cmd);
     $cmd = "ssh root\@$source->{ip} ".$cmd if $source->{ip};
 
     my $raw = run_cmd($cmd);
-    my $index = 1;
+    my $index = 0;
     my $line = "";
     my $last_snap = undef;
     my $line = "";
     my $last_snap = undef;
+    my $old_snap;
 
     while ($raw && $raw =~ s/^(.*?)(\n|$)//) {
        $line = $1;
 
     while ($raw && $raw =~ s/^(.*?)(\n|$)//) {
        $line = $1;
-       $last_snap = $line if $index == 1;
-       if ($index == $max_snap) {
-           $source->{destroy} = 1;
-           last;
-       };
-       $index++;
+       if ($line =~ m/(rep_$name.*)$/) {
+           $last_snap = $1 if (!$last_snap);
+           $old_snap = $1;
+           $index++;
+           if ($index == $max_snap) {
+               $source->{destroy} = 1;
+               last;
+           };
+       }
     }
 
     }
 
-    $line =~ m/^(.+)\@(rep_$name\_.+)(\n|$)/;
-    return ($2, $last_snap) if $2;
+    return ($old_snap, $last_snap) if $last_snap;
 
     return undef;
 }
 
 sub snapshot_add {
 
     return undef;
 }
 
 sub snapshot_add {
-    my ($source, $dest, $name) = @_;
-
-    my $date = get_date();
+    my ($source, $dest, $name, $date) = @_;
 
     my $snap_name = "rep_$name\_".$date;
 
     $source->{new_snap} = $snap_name;
 
 
     my $snap_name = "rep_$name\_".$date;
 
     $source->{new_snap} = $snap_name;
 
-    my $path = $source->{abs_path}."\@".$snap_name;
+    my $path = "$source->{all}\@$snap_name";
 
     my $cmd = "zfs snapshot $path";
 
     my $cmd = "zfs snapshot $path";
-    $cmd = "ssh root\@$source->{ip}  ".$cmd if $source->{ip};
+    $cmd = "ssh root\@$source->{ip}  $cmd" if $source->{ip};
 
     eval{
        run_cmd($cmd);
     };
 
 
     eval{
        run_cmd($cmd);
     };
 
-    if (my $err = $@){
+    if (my $err = $@) {
        snapshot_destroy($source, $dest, 'ssh', $snap_name);
        die "$err\n";
     }
        snapshot_destroy($source, $dest, 'ssh', $snap_name);
        die "$err\n";
     }
-    return $date;
 }
 
 }
 
-sub cron_add {
-    my ($vm) = @_;
+sub write_cron {
+    my ($cfg) = @_;
 
 
-    open(my $fh, '>>', "$CRONJOBS")
-       or die "Could not open file: $!\n";
+    my $text = "SHELL=/bin/sh\n";
+    $text .= "PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\n";
 
 
-    foreach my $name (keys%{$vm}){
-       my $text = "*/$vm->{$name}->{interval} * * * * root ";
-       $text .= "$PATH$PROGNAME sync";
+    my $fh = IO::File->new("> $CRONJOBS");
+    die "Could not open file: $!\n" if !$fh;
+
+    foreach my $source (sort keys%{$cfg}) {
+       foreach my $sync_name (sort keys%{$cfg->{$source}}) {
+           next if $cfg->{$source}->{$sync_name}->{status} ne 'ok';
+       $text .= "$PROG_PATH sync";
        $text .= " -source  ";
        $text .= " -source  ";
-       if ($vm->{$name}->{vmid}) {
-           $text .= "$vm->{$name}->{source_ip}:" if $vm->{$name}->{source_ip};
-           $text .= "$vm->{$name}->{vmid} ";
+       if ($cfg->{$source}->{$sync_name}->{vmid}) {
+           $text .= "$cfg->{$source}->{$sync_name}->{source_ip}:" if $cfg->{$source}->{$sync_name}->{source_ip};
+           $text .= "$cfg->{$source}->{$sync_name}->{vmid} ";
        } else {
        } else {
-           $text .= "$vm->{$name}->{source_ip}:" if $vm->{$name}->{source_ip};
-           $text .= "$vm->{$name}->{source_pool}";
-           $text .= "$vm->{$name}->{source_path}" if $vm->{$name}->{source_path};
+           $text .= "$cfg->{$source}->{$sync_name}->{source_ip}:" if $cfg->{$source}->{$sync_name}->{source_ip};
+           $text .= "$cfg->{$source}->{$sync_name}->{source_pool}";
+           $text .= "$cfg->{$source}->{$sync_name}->{source_path}" if $cfg->{$source}->{$sync_name}->{source_path};
        }
        $text .= " -dest  ";
        }
        $text .= " -dest  ";
-       $text .= "$vm->{$name}->{dest_ip}:" if $vm->{$name}->{dest_ip};
-       $text .= "$vm->{$name}->{dest_pool}";
-       $text .= "$vm->{$name}->{dest_path}" if $vm->{$name}->{dest_path};
-       $text .= " -name $name ";
-       $text .= " -limit $vm->{$name}->{limit}" if $vm->{$name}->{limit};
-       $text .= " -maxsnap $vm->{$name}->{maxsnap}" if $vm->{$name}->{maxsnap};
+       $text .= "$cfg->{$source}->{$sync_name}->{dest_ip}:" if $cfg->{$source}->{$sync_name}->{dest_ip};
+       $text .= "$cfg->{$source}->{$sync_name}->{dest_pool}";
+       $text .= "$cfg->{$source}->{$sync_name}->{dest_path}" if $cfg->{$source}->{$sync_name}->{dest_path};
+       $text .= " -name $sync_name ";
+       $text .= " -limit $cfg->{$source}->{$sync_name}->{limit}" if $cfg->{$source}->{$sync_name}->{limit};
+       $text .= " -maxsnap $cfg->{$source}->{$sync_name}->{maxsnap}" if $cfg->{$source}->{$sync_name}->{maxsnap};
        $text .= "\n";
        $text .= "\n";
-       print($fh $text);
-    }
-    close($fh);
-}
-
-sub cron_del {
-    my ($source, $name) = @_;
-
-    open(my $fh, '<', "$CRONJOBS")
-       or die "Could not open file: $!\n";
-
-    $/ = undef;
-
-    my $text = <$fh>;
-    my $buffer = "";
-    close($fh);
-    while ($text && $text =~ s/^(.*?)(\n|$)//) {
-       my $line = $1.$2;
-       if ($line !~ m/.*$PROGNAME.*$source.*$name.*/){
-           $buffer .= $line;
        }
     }
        }
     }
-    open($fh, '>', "$CRONJOBS")
-       or die "Could not open file: $!\n";
-    print($fh $buffer);
+    die "Can't write to cron\n" if (!print($fh $text));
     close($fh);
 }
 
     close($fh);
 }
 
@@ -604,7 +674,7 @@ sub run_cmd {
     print Dumper $cmd if $DEBUG;
     my $output = `$cmd 2>&1`;
 
     print Dumper $cmd if $DEBUG;
     my $output = `$cmd 2>&1`;
 
-    die $output if 0 != $?;
+    die "COMMAND:\n\t$cmd\nGET ERROR:\n\t$output" if 0 != $?;
 
     chomp($output);
     print Dumper $output if $DEBUG;
 
     chomp($output);
     print Dumper $output if $DEBUG;
@@ -618,14 +688,11 @@ sub parse_disks {
     my $disks;
 
     my $num = 0;
     my $disks;
 
     my $num = 0;
-    my $cmd = "";
-    $cmd .= "ssh root\@$ip " if $ip;
-    $cmd .= "pvesm zfsscan";
-    my $zfs_pools = run_cmd($cmd);
     while ($text && $text =~ s/^(.*?)(\n|$)//) {
        my $line = $1;
        my $disk = undef;
        my $stor = undef;
     while ($text && $text =~ s/^(.*?)(\n|$)//) {
        my $line = $1;
        my $disk = undef;
        my $stor = undef;
+       my $is_disk = $line =~ m/^(virtio|ide|scsi|sata){1}\d+: /;
        if($line =~ m/^(virtio\d+: )(.+:)([A-Za-z0-9\-]+),(.*)$/) {
            $disk = $3;
            $stor = $2;
        if($line =~ m/^(virtio\d+: )(.+:)([A-Za-z0-9\-]+),(.*)$/) {
            $disk = $3;
            $stor = $2;
@@ -640,16 +707,26 @@ sub parse_disks {
            $stor = $2;
        }
 
            $stor = $2;
        }
 
-       if($disk && $disk ne "none" && $disk !~ m/cdrom/ ) {
+       die "disk is not on ZFS Storage\n" if $is_disk && !$disk && $line !~ m/cdrom/;
+
+       if($disk && $line !~ m/none/ && $line !~ m/cdrom/ ) {
            my $cmd = "";
            $cmd .= "ssh root\@$ip " if $ip;
            $cmd .= "pvesm path $stor$disk";
            my $path = run_cmd($cmd);
 
            my $cmd = "";
            $cmd .= "ssh root\@$ip " if $ip;
            $cmd .= "pvesm path $stor$disk";
            my $path = run_cmd($cmd);
 
-           if ($path =~ m/^\/dev\/zvol\/(\w+).*(\/$disk)$/){
+           if ($path =~ m/^\/dev\/zvol\/(\w+).*(\/$disk)$/) {
+
+               my @array = split('/', $1);
+               $disks->{$num}->{pool} = pop(@array);
+               $disks->{$num}->{all} = $disks->{$num}->{pool};
+               if (0 < @array) {
+                   $disks->{$num}->{path} = join('/', @array);
+                   $disks->{$num}->{all} .= "\/$disks->{$num}->{path}";
+               }
+               $disks->{$num}->{last_part} = $disk;
+               $disks->{$num}->{all} .= "\/$disk";
 
 
-               $disks->{$num}->{pool} = $1;
-               $disks->{$num}->{path} = $disk;
                $num++;
 
            } else {
                $num++;
 
            } else {
@@ -657,7 +734,7 @@ sub parse_disks {
            }
        }
     }
            }
        }
     }
-    die "disk is not on ZFS Storage\n" if $num == 0;
+
     return $disks;
 }
 
     return $disks;
 }
 
@@ -665,27 +742,25 @@ sub snapshot_destroy {
     my ($source, $dest, $method, $snap) = @_;
 
     my $zfscmd = "zfs destroy ";
     my ($source, $dest, $method, $snap) = @_;
 
     my $zfscmd = "zfs destroy ";
-    my $name = "$source->{path}\@$snap";
+    my $snapshot = "$source->{all}\@$snap";
 
     eval {
        if($source->{ip} && $method eq 'ssh'){
 
     eval {
        if($source->{ip} && $method eq 'ssh'){
-           run_cmd("ssh root\@$source->{ip} $zfscmd $source->{pool}$name");
+           run_cmd("ssh root\@$source->{ip} $zfscmd $snapshot");
        } else {
        } else {
-           run_cmd("$zfscmd $source->{pool}$name");
+           run_cmd("$zfscmd $snapshot");
        }
     };
     if (my $erro = $@) {
        warn "WARN: $erro";
     }
        }
     };
     if (my $erro = $@) {
        warn "WARN: $erro";
     }
-    if ($dest){
+    if ($dest) {
        my $ssh =  $dest->{ip} ? "ssh root\@$dest->{ip}" : "";
 
        my $ssh =  $dest->{ip} ? "ssh root\@$dest->{ip}" : "";
 
-       my $path = "";
-       $path ="$dest->{path}" if $dest->{path};
+       my $path = "$dest->{all}\/$source->{last_part}";
 
 
-       my @dir = split(/\//, $source->{path});
        eval {
        eval {
-           run_cmd("$ssh $zfscmd $dest->{pool}$path\/$dir[@dir-1]\@$snap ");
+           run_cmd("$ssh $zfscmd $path\@$snap ");
        };
        if (my $erro = $@) {
            warn "WARN: $erro";
        };
        if (my $erro = $@) {
            warn "WARN: $erro";
@@ -698,10 +773,8 @@ sub snapshot_exist {
 
     my $cmd = "";
     $cmd = "ssh root\@$dest->{ip} " if $dest->{ip};
 
     my $cmd = "";
     $cmd = "ssh root\@$dest->{ip} " if $dest->{ip};
-    $cmd .= "zfs list -rt snapshot -Ho name $dest->{pool}";
-    $cmd .= "$dest->{path}" if $dest->{path};
-    my @dir = split(/\//, $source->{path});
-    $cmd .= "\/$dir[@dir-1]\@$source->{old_snap}";
+    $cmd .= "zfs list -rt snapshot -Ho name $dest->{all}";
+    $cmd .= "\/$source->{last_part}\@$source->{old_snap}";
 
     my $text = "";
     eval {$text =run_cmd($cmd);};
 
     my $text = "";
     eval {$text =run_cmd($cmd);};
@@ -717,111 +790,111 @@ sub snapshot_exist {
 }
 
 sub send_image {
 }
 
 sub send_image {
-    my ($source, $dest, $method, $verbose, $limit) = @_;
+    my ($source, $dest, $param) = @_;
 
     my $cmd = "";
 
     $cmd .= "ssh root\@$source->{ip} " if $source->{ip};
     $cmd .= "zfs send ";
 
     my $cmd = "";
 
     $cmd .= "ssh root\@$source->{ip} " if $source->{ip};
     $cmd .= "zfs send ";
-    $cmd .= "-v " if $verbose;
+    $cmd .= "-v " if $param->{verbose};
 
 
-    if($source->{last_snap} && snapshot_exist($source ,$dest, $method)) {
-       $cmd .= "-i $source->{abs_path}\@$source->{old_snap} $source->{abs_path}\@$source->{new_snap} ";
+    if($source->{last_snap} && snapshot_exist($source ,$dest, $param->{method})) {
+       $cmd .= "-i $source->{all}\@$source->{last_snap} $source->{all}\@$source->{new_snap} ";
     } else {
     } else {
-       $cmd .= "$source->{abs_path}\@$source->{new_snap} ";
+       $cmd .= "$source->{all}\@$source->{new_snap} ";
     }
 
     }
 
-    if ($limit){
-       my $bwl = $limit*1024;
+    if ($param->{limit}){
+       my $bwl = $param->{limit}*1024;
        $cmd .= "| cstream  -t $bwl";
     }
     $cmd .= "| ";
     $cmd .= "ssh root\@$dest->{ip} " if $dest->{ip};
        $cmd .= "| cstream  -t $bwl";
     }
     $cmd .= "| ";
     $cmd .= "ssh root\@$dest->{ip} " if $dest->{ip};
-    $cmd .= "zfs recv $dest->{pool}";
-    $cmd .= "$dest->{path}" if $dest->{path};
-
-    my @dir = split(/\//,$source->{path});
-    $cmd .= "\/$dir[@dir-1]\@$source->{new_snap}";
+    $cmd .= "zfs recv $dest->{all}";
+    $cmd .= "\/$source->{last_part}\@$source->{new_snap}";
 
     eval {
        run_cmd($cmd)
     };
 
     if (my $erro = $@) {
 
     eval {
        run_cmd($cmd)
     };
 
     if (my $erro = $@) {
-       snapshot_destroy($source, undef, $method, $source->{new_snap});
+       snapshot_destroy($source, undef, $param->{method}, $source->{new_snap});
        die $erro;
     };
        die $erro;
     };
-
-    if ($source->{vmid}) {
-       if ($method eq "ssh") {
-           send_config($source, $dest,'ssh');
-       }
-    }
 }
 
 
 sub send_config{
     my ($source, $dest, $method) = @_;
 
 }
 
 
 sub send_config{
     my ($source, $dest, $method) = @_;
 
+    my $source_target ="$QEMU_CONF$source->{vmid}.conf";
+    my $dest_target_new ="$CONFIG_PATH$source->{vmid}.conf.$source->{new_snap}";
+
     if ($method eq 'ssh'){
        if ($dest->{ip} && $source->{ip}) {
     if ($method eq 'ssh'){
        if ($dest->{ip} && $source->{ip}) {
-           run_cmd("ssh root\@$dest->{ip} mkdir $VMCONFIG -p");
-           run_cmd("scp root\@$source->{ip}:$QEMU_CONF$source->{vmid}.conf root\@$dest->{ip}:$VMCONFIG$source->{vmid}.conf.$source->{new_snap}");
+           run_cmd("ssh root\@$dest->{ip} mkdir $CONFIG_PATH -p");
+           run_cmd("scp root\@$source->{ip}:$source_target root\@$dest->{ip}:$dest_target_new");
        } elsif ($dest->{ip}) {
        } elsif ($dest->{ip}) {
-           run_cmd("ssh root\@$dest->{ip} mkdir $VMCONFIG -p");
-           run_cmd("scp $QEMU_CONF$source->{vmid}.conf root\@$dest->{ip}:$VMCONFIG$source->{vmid}.conf.$source->{new_snap}");
+           run_cmd("ssh root\@$dest->{ip} mkdir $CONFIG_PATH -p");
+           run_cmd("scp $source_target root\@$dest->{ip}:$dest_target_new");
        } elsif ($source->{ip}) {
        } elsif ($source->{ip}) {
-           run_cmd("mkdir $VMCONFIG -p");
-           run_cmd("scp root\@$source->{ip}:$QEMU_CONF$source->{vmid}.conf $VMCONFIG$source->{vmid}.conf.$source->{new_snap}");
+           run_cmd("mkdir $CONFIG_PATH -p");
+           run_cmd("scp root\@$source->{ip}:$source_target $dest_target_new");
        }
 
        if ($source->{destroy}){
        }
 
        if ($source->{destroy}){
+           my $dest_target_old ="$CONFIG_PATH$source->{vmid}.conf.$source->{old_snap}";
            if($dest->{ip}){
            if($dest->{ip}){
-               run_cmd("ssh root\@$dest->{ip} rm -f $VMCONFIG$source->{vmid}.conf.$source->{old_snap}");
+               run_cmd("ssh root\@$dest->{ip} rm -f $dest_target_old");
            } else {
            } else {
-               run_cmd("rm -f $VMCONFIG$source->{vmid}.conf.$source->{old_snap}");
+               run_cmd("rm -f $dest_target_old");
            }
        }
     }
 }
 
 sub get_date {
            }
        }
     }
 }
 
 sub get_date {
-    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
-    my $datestamp = sprintf ( "%04d-%02d-%02d_%02d:%02d:%02d",$year+1900,$mon+1,$mday,$hour,$min,$sec);
+    my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
+    my $datestamp = sprintf ("%04d-%02d-%02d_%02d:%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec);
 
     return $datestamp;
 }
 
 sub status {
 
     return $datestamp;
 }
 
 sub status {
-    my $cfg = read_from_config("$CONFIG_PATH$CONFIG");
+    my $cfg = read_cron();
 
 
-    my $status_list = sprintf("%-25s%-15s%-10s\n","SOURCE","NAME","STATUS");
+    my $status_list = sprintf("%-25s%-15s%-10s\n", "SOURCE", "NAME", "STATUS");
 
 
-    foreach my $source (sort keys%{$cfg}){
-       foreach my $sync_name (sort keys%{$cfg->{$source}}){
-         my $status;
-
-               my $source_name = $source;
-
-               $source_name = $cfg->{$source}->{$sync_name}->{source_ip}.":".$source if $cfg->{$source}->{$sync_name}->{source_ip};
-
-               if ($cfg->{$source}->{$sync_name}->{locked} eq 'no'){
-                   $status = sprintf("%-10s","OK");
-               } elsif ($cfg->{$source}->{$sync_name}->{locked} eq 'yes' &&
-                        $cfg->{$source}->{$sync_name}->{failure}) {
-                   $status = sprintf("%-10s","sync error");
-               } else {
-                   $status = sprintf("%-10s","syncing");
-               }
+    my $states = read_state();
 
 
-               $status_list .= sprintf("%-25s%-15s", cut_to_width($source_name,25), cut_to_width($sync_name,15));
-               $status_list .= "$status\n";
+    foreach my $source (sort keys%{$cfg}) {
+       foreach my $sync_name (sort keys%{$cfg->{$source}}) {
+           $status_list .= sprintf("%-25s", cut_target_width($source, 25));
+           $status_list .= sprintf("%-15s", cut_target_width($sync_name, 25));
+           $status_list .= "$states->{$source}->{$sync_name}->{state}\n";
        }
     }
 
     return $status_list;
 }
 
        }
     }
 
     return $status_list;
 }
 
+sub enable_job {
+    my ($param) = @_;
+
+    my $job = get_job($param);
+    $job->{state} = "ok";
+    update_state($job);
+    update_cron($job);
+}
+
+sub disable_job {
+    my ($param) = @_;
+
+    my $job = get_job($param);
+    $job->{state} = "stopped";
+    update_state($job);
+    update_cron($job);
+}
 
 my $command = $ARGV[0];
 
 
 my $command = $ARGV[0];
 
@@ -830,23 +903,16 @@ my $commands = {'destroy' => 1,
               'sync' => 1,
               'list' => 1,
               'status' => 1,
               'sync' => 1,
               'list' => 1,
               'status' => 1,
-              'help' => 1};
+              'help' => 1,
+              'enable' => 1,
+              'disable' => 1};
 
 
-if (!$command ||  !$commands->{$command}) {
+if (!$command || !$commands->{$command}) {
     usage();
     die "\n";
 }
 
     usage();
     die "\n";
 }
 
-my $dest = '';
-my $source = '';
-my $verbose = '';
-my $interval = '';
-my $limit = '';
-my $maxsnap = '';
-my $name = '';
-my $skip = '';
-
-my $help_sync = "zfs-zsync sync -dest <string> -source <string> [OPTIONS]\n
+my $help_sync = "$PROGNAME sync -dest <string> -source <string> [OPTIONS]\n
 \twill sync one time\n
 \t-dest\tstring\n
 \t\tthe destination target is like [IP:]<Pool>[/Path]\n
 \twill sync one time\n
 \t-dest\tstring\n
 \t\tthe destination target is like [IP:]<Pool>[/Path]\n
@@ -860,15 +926,12 @@ my $help_sync = "zfs-zsync sync -dest <string> -source <string> [OPTIONS]\n
 \t-source\tstring\n
 \t\tthe source can be an <VMID> or [IP:]<ZFSPool>[/Path]\n";
 
 \t-source\tstring\n
 \t\tthe source can be an <VMID> or [IP:]<ZFSPool>[/Path]\n";
 
-my $help_create = "zfs-zsync create -dest <string> -source <string> [OPTIONS]/n
+my $help_create = "$PROGNAME create -dest <string> -source <string> [OPTIONS]/n
 \tCreate a sync Job\n
 \t-dest\tstringn\n
 \t\tthe destination target is like [IP]:<Pool>[/Path]\n
 \tCreate a sync Job\n
 \t-dest\tstringn\n
 \t\tthe destination target is like [IP]:<Pool>[/Path]\n
-\t-interval\tinteger\n
-\t\tthe interval in min in witch the zfs will sync,
-\t\tdefault is 15 min\n
 \t-limit\tinteger\n
 \t-limit\tinteger\n
-\t\tmax sync speed, default unlimited\n
+\t\tmax sync speed in kBytes/s, default unlimited\n
 \t-maxsnap\tstring\n
 \t\thow much snapshots will be kept before get erased, default 1\n
 \t-name\tstring\n
 \t-maxsnap\tstring\n
 \t\thow much snapshots will be kept before get erased, default 1\n
 \t-name\tstring\n
@@ -878,27 +941,41 @@ my $help_create = "zfs-zsync create -dest <string> -source <string> [OPTIONS]/n
 \t-source\tstring\n
 \t\tthe source can be an <VMID> or [IP:]<ZFSPool>[/Path]\n";
 
 \t-source\tstring\n
 \t\tthe source can be an <VMID> or [IP:]<ZFSPool>[/Path]\n";
 
-my $help_destroy = "zfs-zsync destroy -source <string> [OPTIONS]\n
+my $help_destroy = "$PROGNAME destroy -source <string> [OPTIONS]\n
 \tremove a sync Job from the scheduler\n
 \t-name\tstring\n
 \t\tname of the sync job, if not set it is default\n
 \t-source\tstring\n
 \t\tthe source can be an  <VMID> or [IP:]<ZFSPool>[/Path]\n";
 
 \tremove a sync Job from the scheduler\n
 \t-name\tstring\n
 \t\tname of the sync job, if not set it is default\n
 \t-source\tstring\n
 \t\tthe source can be an  <VMID> or [IP:]<ZFSPool>[/Path]\n";
 
-my $help_help = "zfs-zsync help <cmd> [OPTIONS]\n
+my $help_help = "$PROGNAME help <cmd> [OPTIONS]\n
 \tGet help about specified command.\n
 \t<cmd>\tstring\n
 \t\tCommand name\n
 \t-verbose\tboolean\n
 \t\tVerbose output format.\n";
 
 \tGet help about specified command.\n
 \t<cmd>\tstring\n
 \t\tCommand name\n
 \t-verbose\tboolean\n
 \t\tVerbose output format.\n";
 
-my $help_list = "zfs-zsync list\n
+my $help_list = "$PROGNAME list\n
 \tGet a List of all scheduled Sync Jobs\n";
 
 \tGet a List of all scheduled Sync Jobs\n";
 
-my $help_status = "zfs-zsync status\n
+my $help_status = "$PROGNAME status\n
 \tGet the status of all scheduled Sync Jobs\n";
 
 \tGet the status of all scheduled Sync Jobs\n";
 
-sub help{
+my $help_enable = "$PROGNAME enable -source <string> [OPTIONS]\n
+\tenable a syncjob and reset error\n
+\t-name\tstring\n
+\t\tname of the sync job, if not set it is default\n
+\t-source\tstring\n
+\t\tthe source can be an  <VMID> or [IP:]<ZFSPool>[/Path]\n";
+
+my $help_disable = "$PROGNAME disable -source <string> [OPTIONS]\n
+\tpause a syncjob\n
+\t-name\tstring\n
+\t\tname of the sync job, if not set it is default\n
+\t-source\tstring\n
+\t\tthe source can be an  <VMID> or [IP:]<ZFSPool>[/Path]\n";
+
+sub help {
     my ($command) = @_;
 
     switch($command){
     my ($command) = @_;
 
     switch($command){
@@ -926,52 +1003,41 @@ sub help{
        {
            die "$help_status\n";
        }
        {
            die "$help_status\n";
        }
+       case 'enable'
+       {
+            die "$help_enable\n";
+       }
+       case 'disable'
+       {
+           die "$help_enable\n";
+       }
     }
 
 }
 
     }
 
 }
 
-my $err = GetOptions ('dest=s' => \$dest,
-          'source=s' => \$source,
-          'verbose' => \$verbose,
-          'interval=i' => \$interval,
-          'limit=i' => \$limit,
-          'maxsnap=i' => \$maxsnap,
-          'name=s' => \$name,
-          'skip' => \$skip);
-
-if ($err == 0) {
-    die "can't parse options\n";
-}
+my @arg = @ARGV;
+my $param = parse_argv(@arg);
+
 
 
-my $param;
-$param->{dest} = $dest;
-$param->{source} = $source;
-$param->{verbose} = $verbose;
-$param->{interval} = $interval;
-$param->{limit} = $limit;
-$param->{maxsnap} = $maxsnap;
-$param->{name} = $name;
-$param->{skip} = $skip;
-
-switch($command){
+switch($command) {
     case "destroy"
     {
     case "destroy"
     {
-       die "$help_destroy\n" if !$source;
-       check_target($source);
-       destroy($param);
+       die "$help_destroy\n" if !$param->{source};
+       check_target($param->{source});
+       destroy_job($param);
     }
     case "sync"
     {
     }
     case "sync"
     {
-       die "$help_sync\n" if !$source || !$dest;
-       check_target($source);
-       check_target($dest);
+       die "$help_sync\n" if !$param->{source} || !$param->{dest};
+       check_target($param->{source});
+       check_target($param->{dest});
        sync($param);
     }
     case "create"
     {
        sync($param);
     }
     case "create"
     {
-       die "$help_create\n" if !$source || !$dest;
-       check_target($source);
-       check_target($dest);
+       die "$help_create\n" if !$param->{source} || !$param->{dest};
+       check_target($param->{source});
+       check_target($param->{dest});
        init($param);
     }
     case "status"
        init($param);
     }
     case "status"
@@ -988,33 +1054,47 @@ switch($command){
        if ($help_command && $commands->{$help_command}) {
            print help($help_command);
        }
        if ($help_command && $commands->{$help_command}) {
            print help($help_command);
        }
-       if ($verbose){
+       if ($param->{verbose} == 1){
            exec("man $PROGNAME");
        } else {
            usage(1);
        }
     }
            exec("man $PROGNAME");
        } else {
            usage(1);
        }
     }
+    case "enable"
+    {
+       die "$help_enable\n" if !$param->{source};
+       check_target($param->{source});
+       enable_job($param);
+    }
+    case "disable"
+    {
+       die "$help_disable\n" if !$param->{source};
+       check_target($param->{source});
+       disable_job($param);
+    }
 }
 
 }
 
-sub usage{
+sub usage {
     my ($help) = @_;
 
     print("ERROR:\tno command specified\n") if !$help;
     print("USAGE:\t$PROGNAME <COMMAND> [ARGS] [OPTIONS]\n");
     my ($help) = @_;
 
     print("ERROR:\tno command specified\n") if !$help;
     print("USAGE:\t$PROGNAME <COMMAND> [ARGS] [OPTIONS]\n");
-    print("\tpve-zsync help [<cmd>] [OPTIONS]\n\n");
-    print("\tpve-zsync create -dest <string> -source <string> [OPTIONS]\n");
-    print("\tpve-zsync destroy -source <string> [OPTIONS]\n");
-    print("\tpve-zsync list\n");
-    print("\tpve-zsync status\n");
-    print("\tpve-zsync sync -dest <string> -source <string> [OPTIONS]\n");
+    print("\t$PROGNAME help [<cmd>] [OPTIONS]\n\n");
+    print("\t$PROGNAME create -dest <string> -source <string> [OPTIONS]\n");
+    print("\t$PROGNAME destroy -source <string> [OPTIONS]\n");
+    print("\t$PROGNAME disable -source <string> [OPTIONS]\n");
+    print("\t$PROGNAME enable -source <string> [OPTIONS]\n");
+    print("\t$PROGNAME list\n");
+    print("\t$PROGNAME status\n");
+    print("\t$PROGNAME sync -dest <string> -source <string> [OPTIONS]\n");
 }
 
 }
 
-sub check_target{
+sub check_target {
     my ($target) = @_;
 
     chomp($target);
 
     my ($target) = @_;
 
     chomp($target);
 
-    if($target !~ m/(\d+.\d+.\d+.\d+:)?([\w\-\_\/]+)(\/.+)?/){
+    if($target !~ m/(\d+.\d+.\d+.\d+:)?([\w\-\_\/]+)(\/.+)?/) {
        print("ERROR:\t$target is not valid.\n\tUse [IP:]<ZFSPool>[/Path]!\n");
        return 1;
     }
        print("ERROR:\t$target is not valid.\n\tUse [IP:]<ZFSPool>[/Path]!\n");
        return 1;
     }
@@ -1029,9 +1109,9 @@ pve-zsync - PVE ZFS Replication Manager
 
 =head1 SYNOPSIS
 
 
 =head1 SYNOPSIS
 
-zfs-zsync <COMMAND> [ARGS] [OPTIONS]
+pve-zsync <COMMAND> [ARGS] [OPTIONS]
 
 
-zfs-zsync help <cmd> [OPTIONS]
+pve-zsync help <cmd> [OPTIONS]
 
        Get help about specified command.
 
 
        Get help about specified command.
 
@@ -1043,59 +1123,78 @@ zfs-zsync help <cmd> [OPTIONS]
 
                Verbose output format.
 
 
                Verbose output format.
 
-zfs-zsync create -dest <string> -source <string> [OPTIONS]
+pve-zsync create -dest <string> -source <string> [OPTIONS]
 
 
-          Create a sync Job
+        Create a sync Job
 
 
-          -dest      string
+        -dest      string
 
                the destination target is like [IP]:<Pool>[/Path]
 
 
                the destination target is like [IP]:<Pool>[/Path]
 
-          -interval  integer
-
-               the interval in min in witch the zfs will sync, default is 15 min
+        -limit     integer
 
 
-          -limit     integer
-
-               max sync speed, default unlimited
+               max sync speed in kBytes/s, default unlimited
 
 
-          -maxsnap   string
+        -maxsnap   string
 
                how much snapshots will be kept before get erased, default 1
 
 
                how much snapshots will be kept before get erased, default 1
 
-          -name      string
+        -name      string
 
                name of the sync job, if not set it is default
 
 
                name of the sync job, if not set it is default
 
-          -skip      boolean
+        -skip      boolean
 
                if this flag is set it will skip the first sync
 
 
                if this flag is set it will skip the first sync
 
-          -source    string
+        -source    string
 
                the source can be an <VMID> or [IP:]<ZFSPool>[/Path]
 
 
                the source can be an <VMID> or [IP:]<ZFSPool>[/Path]
 
-zfs-zsync destroy -source <string> [OPTIONS]
+pve-zsync destroy -source <string> [OPTIONS]
 
 
-          remove a sync Job from the scheduler
+        remove a sync Job from the scheduler
 
 
-          -name      string
+        -name      string
 
                name of the sync job, if not set it is default
 
 
                name of the sync job, if not set it is default
 
-          -source    string
+        -source    string
 
                 the source can be an  <VMID> or [IP:]<ZFSPool>[/Path]
 
 
                 the source can be an  <VMID> or [IP:]<ZFSPool>[/Path]
 
-zfs-zsync list
+pve-zsync disable -source <string> [OPTIONS]
+
+        pause a sync job
+
+        -name      string
+
+               name of the sync job, if not set it is default
+
+        -source    string
+
+                the source can be an  <VMID> or [IP:]<ZFSPool>[/Path]
+
+pve-zsync enable -source <string> [OPTIONS]
+
+        enable a syncjob and reset error
+
+        -name      string
+
+               name of the sync job, if not set it is default
+
+        -source    string
+
+                the source can be an  <VMID> or [IP:]<ZFSPool>[/Path]
+pve-zsync list
 
        Get a List of all scheduled Sync Jobs
 
 
        Get a List of all scheduled Sync Jobs
 
-zfs-zsync status
+pve-zsync status
 
        Get the status of all scheduled Sync Jobs
 
 
        Get the status of all scheduled Sync Jobs
 
-zfs-zsync sync -dest <string> -source <string> [OPTIONS]
+pve-zsync sync -dest <string> -source <string> [OPTIONS]
 
        will sync one time
 
 
        will sync one time
 
@@ -1107,16 +1206,16 @@ zfs-zsync sync -dest <string> -source <string> [OPTIONS]
 
                max sync speed in kBytes/s, default unlimited
 
 
                max sync speed in kBytes/s, default unlimited
 
-         -maxsnap   integer
+        -maxsnap   integer
 
                how much snapshots will be kept before get erased, default 1
 
 
                how much snapshots will be kept before get erased, default 1
 
-         -name      string
+        -name      string
 
                name of the sync job, if not set it is default.
                It is only necessary if scheduler allready contains this source.
 
 
                name of the sync job, if not set it is default.
                It is only necessary if scheduler allready contains this source.
 
-          -source    string
+        -source    string
 
                the source can be an <VMID> or [IP:]<ZFSPool>[/Path]
 
 
                the source can be an <VMID> or [IP:]<ZFSPool>[/Path]
 
@@ -1124,6 +1223,8 @@ zfs-zsync sync -dest <string> -source <string> [OPTIONS]
 
 This Tool helps you to sync your VM or directory which stored on ZFS between 2 servers.
 This tool also has the capability to add jobs to cron so the sync will be automatically done.
 
 This Tool helps you to sync your VM or directory which stored on ZFS between 2 servers.
 This tool also has the capability to add jobs to cron so the sync will be automatically done.
+The default syncing interval is set to 15 min, if you want to change this value you can do this in /etc/cron.d/pve-zsync.
+To config cron see man crontab.
 
 =head2 PVE ZFS Storage sync Tool
 
 
 =head2 PVE ZFS Storage sync Tool
 
@@ -1132,13 +1233,15 @@ This Tool can get remote pool on other PVE or send Pool to others ZFS machines
 =head1 EXAMPLES
 
 add sync job from local VM to remote ZFS Server
 =head1 EXAMPLES
 
 add sync job from local VM to remote ZFS Server
-zfs-zsync -source=100 -dest=192.168.1.2:zfspool
+pve-zsync create -source=100 -dest=192.168.1.2:zfspool
 
 =head1 IMPORTANT FILES
 
 
 =head1 IMPORTANT FILES
 
-Where the cron jobs are stored                            /etc/cron.d/pve-zsync
-Where the VM config get copied on the destination machine /var/pve-zsync
-Where the config is stored                                /var/pve-zsync
+Cron jobs and config are stored at                      /etc/cron.d/pve-zsync
+
+The VM config get copied on the destination machine to  /var/lib/pve-zsync/
+
+=head1 COPYRIGHT AND DISCLAIMER
 
 Copyright (C) 2007-2015 Proxmox Server Solutions GmbH
 
 
 Copyright (C) 2007-2015 Proxmox Server Solutions GmbH