5
0
mirror of git://git.proxmox.com/git/qemu-server.git synced 2024-12-22 13:34:06 +03:00
qemu-server/qmextract
Thomas Lamprecht 424f9940af remove legacy sparsecp
sparsecp gets only used in qmextract, which is part of the old backup
method (pre PVE 2.3).
Do not remove qmextract for now people could still have backups from
< PVE 2.3 around.
They could be restored manually, but we shouldn't make restoring
complicated. Thus replace sparsecp with `cp sparse=always`.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2017-08-23 10:03:37 +02:00

221 lines
5.4 KiB
Perl
Executable File

#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
use File::Path;
use IO::File;
use PVE::INotify;
use PVE::JSONSchema;
use PVE::Tools;
use PVE::Cluster;
use PVE::RPCEnvironment;
use PVE::Storage;
use PVE::QemuServer;
$ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin';
die "please run as root\n" if $> != 0;
my @std_opts = ('storage=s', 'pool=s', 'info', 'prealloc');
sub print_usage {
print STDERR "usage: $0 [--storage=<storeid>] [--pool=<poolid>] [--info] [--prealloc] <archive> <vmid>\n\n";
}
my $opts = {};
if (!GetOptions ($opts, @std_opts)) {
print_usage ();
exit (-1);
}
PVE::INotify::inotify_init();
my $rpcenv = PVE::RPCEnvironment->init('cli');
$rpcenv->init_request();
$rpcenv->set_language($ENV{LANG});
$rpcenv->set_user('root@pam');
sub extract_archive {
# NOTE: this is run as tar subprocess (--to-command)
$SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = $SIG{PIPE} = sub {
die "interrupted by signal\n";
};
my $filename = $ENV{TAR_FILENAME};
die "got strange environment - no TAR_FILENAME\n" if !$filename;
my $filesize = $ENV{TAR_SIZE};
die "got strange file size '$filesize'\n" if !$filesize;
my $tmpdir = $ENV{VZDUMP_TMPDIR};
die "got strange environment - no VZDUMP_TMPDIR\n" if !$tmpdir;
my $filetype = $ENV{TAR_FILETYPE} || 'none';
die "got strange filetype '$filetype'\n" if $filetype ne 'f';
my $vmid = $ENV{VZDUMP_VMID};
PVE::JSONSchema::pve_verify_vmid($vmid);
my $user = $ENV{VZDUMP_USER};
$rpcenv->check_user_enabled($user);
if ($opts->{info}) {
print STDERR "reading archive member '$filename'\n";
} else {
print STDERR "extracting '$filename' from archive\n";
}
my $conffile = "$tmpdir/qemu-server.conf";
my $statfile = "$tmpdir/qmrestore.stat";
if ($filename eq 'qemu-server.conf') {
my $outfd = IO::File->new($conffile, "w") ||
die "unable to write file '$conffile'\n";
while (defined(my $line = <>)) {
print $outfd $line;
print STDERR "CONFIG: $line" if $opts->{info};
}
$outfd->close();
exit(0);
}
if ($opts->{info}) {
exec 'dd', 'bs=256K', "of=/dev/null";
die "couldn't exec dd: $!\n";
}
my $conffd = IO::File->new($conffile, "r") ||
die "unable to read file '$conffile'\n";
my $map;
while (defined(my $line = <$conffd>)) {
if ($line =~ m/^\#vzdump\#map:(\S+):(\S+):(\d+):(\S*):$/) {
$map->{$2} = { virtdev => $1, size => $3, storeid => $4 };
}
}
close($conffd);
my $statfd = IO::File->new($statfile, "a") ||
die "unable to open file '$statfile'\n";
if ($filename !~ m/^.*\.([^\.]+)$/){
die "got strange filename '$filename'\n";
}
my $format = $1;
my $path;
if (!$map) {
print STDERR "restoring old style vzdump archive - " .
"no device map inside archive\n";
die "can't restore old style archive to storage '$opts->{storage}'\n"
if defined($opts->{storage}) && $opts->{storage} ne 'local';
my $dir = "/var/lib/vz/images/$vmid";
mkpath $dir;
$path = "$dir/$filename";
print $statfd "vzdump::$path\n";
$statfd->close();
} else {
my $info = $map->{$filename};
die "no vzdump info for '$filename'\n" if !$info;
if ($filename !~ m/^vm-disk-$info->{virtdev}\.([^\.]+)$/){
die "got strange filename '$filename'\n";
}
if ($filesize != $info->{size}) {
die "detected size difference for '$filename' " .
"($filesize != $info->{size})\n";
}
# check permission for all used storages
my $pool = $opts->{pool};
if ($user ne 'root@pam') {
if (defined($opts->{storage})) {
my $sid = $opts->{storage} || 'local';
$rpcenv->check($user, "/storage/$sid", ['Datastore.AllocateSpace']);
} else {
foreach my $fn (keys %$map) {
my $fi = $map->{$fn};
my $sid = $fi->{storeid} || 'local';
$rpcenv->check($user, "/storage/$sid", ['Datastore.AllocateSpace']);
}
}
}
my $storeid;
if (defined($opts->{storage})) {
$storeid = $opts->{storage} || 'local';
} else {
$storeid = $info->{storeid} || 'local';
}
my $cfg = PVE::Storage::config();
my $scfg = PVE::Storage::storage_config($cfg, $storeid);
my $alloc_size = int(($filesize + 1024 - 1)/1024);
if ($scfg->{type} eq 'dir' || $scfg->{type} eq 'nfs') {
# hack: we just alloc a small file (32K) - we overwrite it anyways
$alloc_size = 32;
} else {
die "unable to restore '$filename' to storage '$storeid'\n" .
"storage type '$scfg->{type}' does not support format '$format\n"
if $format ne 'raw';
}
my $volid = PVE::Storage::vdisk_alloc($cfg, $storeid, $vmid,
$format, undef, $alloc_size);
print STDERR "new volume ID is '$volid'\n";
print $statfd "vzdump:$info->{virtdev}:$volid\n";
$statfd->close();
$path = PVE::Storage::path($cfg, $volid);
}
print STDERR "restore data to '$path' ($filesize bytes)\n";
if ($opts->{prealloc} || $format ne 'raw' || (-b $path)) {
exec 'dd', 'ibs=256K', 'obs=256K', "of=$path";
die "couldn't exec dd: $!\n";
} else {
exec '/bin/cp', '--sparse=always', '/dev/stdin', $path;
die "couldn't exec cp: $!\n";
}
}
if (scalar(@ARGV) == 2) {
my $archive = shift;
my $vmid = shift;
# fixme: use API call
PVE::JSONSchema::pve_verify_vmid($vmid);
PVE::Cluster::check_cfs_quorum();
PVE::QemuServer::restore_archive($archive, $vmid, 'root@pam', $opts);
} elsif (scalar(@ARGV) == 0 && $ENV{TAR_FILENAME}) {
extract_archive();
} else {
print_usage ();
exit(-1);
}
exit(0);