package Storage::MimeStorage; use AgentConfig; use POSIX; use MIME::Lite; use IPC::Run; use Storage::Splitter; use strict; use Storage::Storage; use vars qw|@ISA|; @ISA = qw|Storage::Storage|; sub _init { my ($self, %options) = @_; $self->SUPER::_init(%options); $self->{output_file} = $options{output_file}; $self->{gzip} = $options{gzip}; $self->{split_size} = $options{split_size}; $self->{not_compatible_mysql_323} = 1; $self->{bundles} = []; Logging::info("-" x 60); Logging::info("MIME storage initialized."); Logging::info("Destination file: $self->{output_file}"); Logging::info("Gzip: " . ($self->{gzip} ? "yes" : "no")); Logging::info("Backup split size: " . ($self->{split_size} || "do not split")); Logging::info("-" x 60); } sub addDb { my ($self, $proposedId, %options) = @_; $options{not_compatible_mysql_323} = $self->{not_compatible_mysql_323}; my $bundle = Storage::Bundle::createDbBundle(%options); push @{$self->{bundles}}, [$proposedId, $bundle] if $bundle; return $proposedId; } sub addTar { my ($self, $proposedId, %options) = @_; return unless -d $options{'directory'}; my $bundle = Storage::Bundle::createTarBundle(%options); push @{$self->{bundles}}, [$proposedId, $bundle] if $bundle; return $proposedId; } sub _getMimeWriter { my ($self, $descriptor) = @_; return sub { my $msg = MIME::Lite->new(Type => 'multipart/related'); $msg->preamble(''); my $dump_dir = AgentConfig::get("DUMP_D"); my $tmp_dir = (AgentConfig::get("os") eq "FreeBSD") ? "$dump_dir/var/tmp" : "$dump_dir/tmp"; if (! -d $tmp_dir) { system("mkdir -p ".$tmp_dir); chown 0 + getpwnam("psaadm"), 0 + getgrnam("psaadm"), $tmp_dir; chmod S_IRUSR|S_IWUSR|S_IXUSR, $tmp_dir; } my $fileName = $dump_dir . POSIX::tmpnam(); open DESCRIPTOR, ">$fileName"; $descriptor->{'PRINT_TREE'}->(\*DESCRIPTOR); close DESCRIPTOR; $msg->attach('Type' => 'text/xml', Path => $fileName, Filename => 'dump.xml'); foreach my $ptrRow (@{$self->{bundles}}) { my $id = $ptrRow->[0]; my $bundle = $ptrRow->[1]; Logging::info("Dumping MIME part $id"); $msg->attach(Type => 'application/octet-stream', Encoding => "binary", Id => $id, Filename => $id, GenerateFH => sub { return $bundle->run() }, CloseFH => sub { close $_[0]; $bundle->cleanup(); }, TmpFile => $fileName); } binmode STDOUT; $msg->print(\*STDOUT); unlink($fileName); } } sub finish { my ($self, $descriptor) = @_; Logging::info("Writing MIME file"); my @cmd; push @cmd, $self->_getMimeWriter($descriptor); if ($self->{gzip}) { push @cmd, "|", ["gzip"]; } my $files; #allocating filehandle for creating pipe from subprocess my $newhandle = POSIX::open("/dev/null", O_RDWR, 0666); push @cmd, "|", \&Storage::Splitter::run, "$newhandle>", \$files, init => sub {Storage::Splitter::init_process($newhandle, $self->{split_size}, $self->{output_file})}; my $h = IPC::Run::harness(@cmd); if (!$h->run()) { POSIX::close($newhandle); Logging::error("Failed to create MIME message"); return 1; } POSIX::close($newhandle); if ($h->result()) { Logging::error("Unable to create backup"); return $h->result(); } Logging::info("MIME writing finished"); return 0; } 1; # Local Variables: # mode: cperl # cperl-indent-level: 2 # indent-tabs-mode: nil # tab-width: 4 # End: