#!@PERL@
-# Copyright (c) 2008, 2009, 2010 Zmanda, Inc. All Rights Reserved.
+# Copyright (c) 2008-2012 Zmanda, Inc. All Rights Reserved.
#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 as published
-# by the Free Software Foundation.
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
use Sys::Hostname;
use Symbol;
use IO::Handle;
+use MIME::Base64 ();
use Amanda::Constants;
use Amanda::Config qw( :init :getconf config_dir_relative );
use Amanda::Debug qw( :logging );
use Amanda::Paths;
use Amanda::Util qw( :constants :quoting);
+use Amanda::MainLoop qw( :GIOCondition );
sub new {
my $class = shift;
} else {
$self->{device} = $disk;
}
- if ($self->{disk} =~ /^\\\\/) {
- $self->{unc} = 1;
- } else {
- $self->{unc} = 0;
- }
$self->{level} = [ @{$level} ];
$self->{index} = $index;
$self->{message} = $message;
next;
}
while (<FF>) {
+ if (defined $self->{'subdir'}) {
+ $_ =~ s/^\./$self->{'subdir'}/;
+ }
print INC_FILE;
}
close(FF);
for(my $i=1;defined $ARGV[$i]; $i++) {
my $param = $ARGV[$i];
$param =~ /^(.*)$/;
- print INC_FILE "$1\n";
+ $_ = $1;
+ if (defined $self->{'subdir'}) {
+ $_ =~ s/^\./$self->{'subdir'}/;
+ }
+ print INC_FILE "$_\n";
}
close INC_FILE;
}
while (<FF>) {
chomp;
+ if ($self->{action} eq "restore" and
+ defined $self->{'subdir'}) {
+ $_ =~ s/^\./$self->{'subdir'}/;
+ }
push @{$self->{include}}, $_;
}
close(FF);
for(my $i=1;defined $ARGV[$i]; $i++) {
my $param = $ARGV[$i];
$param =~ /^(.*)$/;
+ $_ = $1;
+ if (defined $self->{'subdir'}) {
+ $_ =~ s/^\./$self->{'subdir'}/;
+ }
push @{$self->{include}}, $1;
}
}
$to_parse = $self->{device} if !defined $to_parse;;
return if !defined $to_parse;
+ if ($to_parse =~ /^\\\\/) {
+ $self->{unc} = 1;
+ } else {
+ $self->{unc} = 0;
+ }
if ($self->{unc}) {
if ($to_parse =~ m,^(\\\\[^\\]+\\[^\\]+)\\(.*)$,) {
$self->{domain} = $domain if defined $domain && $domain ne "";
my ($username, $password) = split('%', $userpasswd, 2);
$self->{username} = $username;
+ if ($password =~ /^6G\!dr(.*)/) {
+ my $base64 = $1;
+ $password = MIME::Base64::decode($base64);
+ }
$self->{password} = $password;
$self->{password} = undef if (defined $password && $password eq "");
} else {
sub command_selfcheck {
my $self = shift;
- $self->print_to_server("disk " . quote_string($self->{disk}));
+ $self->print_to_server("disk " . quote_string($self->{disk}),
+ $Amanda::Script_App::GOOD);
$self->print_to_server("amsamba version " . $Amanda::Constants::VERSION,
$Amanda::Script_App::GOOD);
print "OK " . $self->{device} . "\n";
print "OK " . $self->{directory} . "\n" if defined $self->{directory};
- my ($child_rdr, $parent_wtr);
+ my ($password_rdr, $password_wtr);
if (defined $self->{password}) {
# Don't set close-on-exec
$^F=10;
- pipe($child_rdr, $parent_wtr);
+ pipe($password_rdr, $password_wtr);
$^F=2;
- $parent_wtr->autoflush(1);
+ $password_wtr->autoflush(1);
}
my($wtr, $rdr, $err);
$err = Symbol::gensym;
if ($pid == 0) {
#child
if (defined $self->{password}) {
- my $ff = $child_rdr->fileno;
- debug("child_rdr $ff");
- $parent_wtr->close();
- $ENV{PASSWD_FD} = $child_rdr->fileno;
+ my $ff = $password_rdr->fileno;
+ debug("password_rdr $ff");
+ $password_wtr->close();
+ $ENV{PASSWD_FD} = $password_rdr->fileno;
}
close(1);
close(2);
}
#parent
if (defined $self->{password}) {
- my $ff = $parent_wtr->fileno;
- debug("parent_wtr $ff");
- $parent_wtr->print($self->{password});
- $parent_wtr->close();
- $child_rdr->close();
+ my $ff = $password_wtr->fileno;
+ debug("password_wtr $ff");
+ $password_wtr->print($self->{password});
+ $password_wtr->close();
+ $password_rdr->close();
} else {
debug("No password");
}
$self->validate_inexclude();
my $level = $self->{level}[0];
- my ($child_rdr, $parent_wtr);
+ my ($password_rdr, $password_wtr);
if (defined $self->{password}) {
# Don't set close-on-exec
$^F=10;
- pipe($child_rdr, $parent_wtr);
+ pipe($password_rdr, $password_wtr);
$^F=2;
- $parent_wtr->autoflush(1);
+ $password_wtr->autoflush(1);
}
my($wtr, $rdr, $err);
$err = Symbol::gensym;
if ($pid == 0) {
#child
if (defined $self->{password}) {
- my $ff = $child_rdr->fileno;
- debug("child_rdr $ff");
- $parent_wtr->close();
- $ENV{PASSWD_FD} = $child_rdr->fileno;
+ my $ff = $password_rdr->fileno;
+ debug("password_rdr $ff");
+ $password_wtr->close();
+ $ENV{PASSWD_FD} = $password_rdr->fileno;
}
close(0);
close(1);
}
#parent
if (defined $self->{password}) {
- my $ff = $parent_wtr->fileno;
- debug("parent_wtr $ff");
+ my $ff = $password_wtr->fileno;
+ debug("password_wtr $ff");
debug("password $self->{password}");
- $parent_wtr->print($self->{password});
- $parent_wtr->close();
- $child_rdr->close();
+ $password_wtr->print($self->{password});
+ $password_wtr->close();
+ $password_rdr->close();
}
close($wtr);
close($rdr);
}
}
+sub send_empty_tar_file {
+ my $self = shift;
+ my ($out1, $out2) = @_;
+ my $out;
+ my $buf;
+ my $size;
+
+ Amanda::Debug::debug("Create empty archive with: tar --create --file=- --files-from=/dev/null");
+ open2($out, undef, "tar", "--create", "--file=-", "--files-from=/dev/null");
+
+ while(($size = sysread($out, $buf, 32768))) {
+ syswrite($out1, $buf, $size);
+ syswrite($out2, $buf, $size);
+ }
+}
+
sub command_backup {
my $self = shift;
$self->findpass();
$self->validate_inexclude();
- my $pid_tee = open3(\*INDEX_IN, '>&STDOUT', \*INDEX_TEE, "-");
- if ($pid_tee == 0) {
- close(INDEX_IN);
- close(INDEX_TEE);
- my $buf;
- my $size = -1;
- while (($size = POSIX::read(0, $buf, 32768)) > 0) {
- POSIX::write(1, $buf, $size);
- POSIX::write(2, $buf, $size);
- }
- exit 0;
- }
- my ($child_rdr, $parent_wtr);
+ my ($password_rdr, $password_wtr);
if (defined $self->{password}) {
# Don't set close-on-exec
$^F=10;
- pipe($child_rdr, $parent_wtr);
+ pipe($password_rdr, $password_wtr);
$^F=2;
- $parent_wtr->autoflush(1);
+ $password_wtr->autoflush(1);
}
- my($wtr, $err);
- $err = Symbol::gensym;
- my $pid = open3($wtr, ">&INDEX_IN", $err, "-");
+ my($smbclient_wtr, $smbclient_rdr, $smbclient_err);
+ $smbclient_err = Symbol::gensym;
+ my $pid = open3($smbclient_wtr, $smbclient_rdr, $smbclient_err, "-");
if ($pid == 0) {
#child
if (defined $self->{password}) {
- my $ff = $child_rdr->fileno;
- debug("child_rdr $ff");
- $parent_wtr->close();
- $ENV{PASSWD_FD} = $child_rdr->fileno;
+ my $ff = $password_rdr->fileno;
+ debug("password_rdr $ff");
+ $password_wtr->close();
+ $ENV{PASSWD_FD} = $password_rdr->fileno;
}
- close(0);
my @ARGV = ();
push @ARGV, $self->{smbclient}, $self->{share};
push @ARGV, "" if (!defined($self->{password}));
}
if (defined $self->{password}) {
- my $ff = $parent_wtr->fileno;
- debug("parent_wtr $ff");
- debug("password $self->{password}");
- $parent_wtr->print($self->{password});
- $parent_wtr->close();
- $child_rdr->close();
+ my $ff = $password_wtr->fileno;
+ debug("password_wtr $ff");
+ $password_wtr->print($self->{password});
+ $password_wtr->close();
+ $password_rdr->close();
} else {
debug("No password");
}
- close($wtr);
+ close($smbclient_wtr);
#index process
- my $index;
+ my $index_rdr;
+ my $index_wtr;
debug("$self->{gnutar} -tf -");
- my $pid_index1 = open2($index, '<&INDEX_TEE', $self->{gnutar}, "-tf", "-");
- close(INDEX_IN);
+ my $pid_index1 = open2($index_rdr, $index_wtr, $self->{gnutar}, "-tf", "-");
my $size = -1;
- my $index_fd = $index->fileno;
+ my $index_fd = $index_rdr->fileno;
debug("index $index_fd");
+ my $indexout_fd;
if (defined($self->{index})) {
- my $indexout_fd;
open($indexout_fd, '>&=4') ||
$self->print_to_server_and_die("Can't open indexout_fd: $!",
$Amanda::Script_App::ERROR);
- $self->parse_backup($index, $self->{mesgout}, $indexout_fd);
- close($indexout_fd);
- }
- else {
- $self->parse_backup($index_fd, $self->{mesgout}, undef);
}
- close($index);
- while (<$err>) {
- chomp;
- debug("stderr: " . $_);
- next if /^Domain=/;
- next if /^tarmode is now /;
- next if /dumped (\d+) files and directories/;
+ my $file_to_close = 3;
+ my $smbclient_stdout_src = Amanda::MainLoop::fd_source($smbclient_rdr,
+ $G_IO_IN|$G_IO_HUP|$G_IO_ERR);
+ my $smbclient_stderr_src = Amanda::MainLoop::fd_source($smbclient_err,
+ $G_IO_IN|$G_IO_HUP|$G_IO_ERR);
+ my $index_tar_stdout_src = Amanda::MainLoop::fd_source($index_rdr,
+ $G_IO_IN|$G_IO_HUP|$G_IO_ERR);
+
+ my $smbclient_stdout_done = 0;
+ my $smbclient_stderr_done = 0;
+ my $data_size = 0;
+ my $nb_files = 0;
+ $smbclient_stdout_src->set_callback(sub {
+ my $buf;
+ my $blocksize = -1;
+ $blocksize = sysread($smbclient_rdr, $buf, 32768);
+ if (!$blocksize) {
+ $file_to_close--;
+ $smbclient_stdout_src->remove();
+ $smbclient_stdout_done = 1;
+ if ($smbclient_stderr_done) {
+ if ($data_size == 0 and $nb_files == 0 and $size == 0) {
+ $self->send_empty_tar_file(*STDOUT, $index_wtr);
+ }
+ close($index_wtr);
+ close(STDOUT);
+ }
+ close($smbclient_rdr);
+ Amanda::MainLoop::quit() if $file_to_close == 0;
+ return;
+ }
+ $data_size += $blocksize;
+ syswrite(STDOUT, $buf, $blocksize);
+ syswrite($index_wtr, $buf, $blocksize);
+ });
+
+ $smbclient_stderr_src->set_callback(sub {
+ my $line = <$smbclient_err>;
+ if (!defined $line) {
+ $file_to_close--;
+ $smbclient_stderr_src->remove();
+ $smbclient_stderr_done = 1;
+ if ($smbclient_stdout_done) {
+ if ($data_size == 0 and $nb_files == 0 and $size == 0) {
+ $self->send_empty_tar_file(*STDOUT, $index_wtr);
+ }
+ close($index_wtr);
+ close(STDOUT);
+ }
+ close ($smbclient_err);
+ Amanda::MainLoop::quit() if $file_to_close == 0;
+ return;
+ }
+ chomp $line;
+ debug("stderr: " . $line);
+ return if $line =~ /^Domain=/;
+ return if $line =~ /^tarmode is now /;
+ if ($line =~ /dumped (\d+) files and directories/) {
+ $nb_files = $1;
+ return;
+ }
# message if samba server is configured with 'security = share'
- next if /Server not using user level security and no password supplied./;
- if (/^Total bytes written: (\d*)/) {
+ return if $line =~$line =~ /Server not using user level security and no password supplied./;
+ if ($line =~ /^Total bytes written: (\d*)/) {
$size = $1;
+ return;
+ }
+ $self->print_to_server("smbclient: $line", $Amanda::Script_App::ERROR);
+ });
+
+ $index_tar_stdout_src->set_callback(sub {
+ my $line = <$index_rdr>;
+ if (!defined $line) {
+ $file_to_close--;
+ $index_tar_stdout_src->remove();
+ close($index_rdr);
+ close($indexout_fd);
+ Amanda::MainLoop::quit() if $file_to_close == 0;
+ return;
+ }
+ if ($line =~ /^\.\//) {
+ if(defined($indexout_fd)) {
+ if(defined($self->{index})) {
+ $line =~ s/^\.//;
+ print $indexout_fd $line;
+ }
+ }
} else {
- $self->print_to_server("smbclient: $_",
- $Amanda::Script_App::ERROR);
+ chomp $line;
+ $self->print_to_server($line, $Amanda::Script_App::ERROR);
}
- }
+ });
+
+ Amanda::MainLoop::run();
+
if ($size >= 0) {
my $ksize = $size / 1024;
if ($ksize < 32) {
$self->validate_inexclude();
$self->findpass();
push @cmd, $self->{smbclient}, $self->{share};
+ push @cmd, "-D", $self->{'subdir'} if defined $self->{'subdir'};
push @cmd, "" if (!defined $self->{password});
push @cmd, "-d", "0",
"-U", $self->{username};