]> git.proxmox.com Git - qemu-server.git/blame - qmextract
bump version to 2.0-72
[qemu-server.git] / qmextract
CommitLineData
3e16d5fc
DM
1#!/usr/bin/perl -w
2
3use strict;
4use Getopt::Long;
5use File::Path;
6use IO::File;
a0d1b1a2 7use PVE::INotify;
3e16d5fc
DM
8use PVE::JSONSchema;
9use PVE::Tools;
10use PVE::Cluster qw(cfs_read_file);
a0d1b1a2 11use PVE::RPCEnvironment;
3e16d5fc
DM
12use PVE::QemuServer;
13
a0d1b1a2
DM
14$ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin';
15
16die "please run as root\n" if $> != 0;
17
18my @std_opts = ('storage=s', 'pool=s', 'info', 'prealloc');
3e16d5fc
DM
19
20sub print_usage {
a0d1b1a2 21 print STDERR "usage: $0 [--storage=<storeid>] [--pool=<poolid>] [--info] [--prealloc] <archive> <vmid>\n\n";
3e16d5fc
DM
22}
23
24my $opts = {};
25if (!GetOptions ($opts, @std_opts)) {
26 print_usage ();
27 exit (-1);
28}
29
a0d1b1a2
DM
30PVE::INotify::inotify_init();
31
32my $rpcenv = PVE::RPCEnvironment->init('cli');
33
34$rpcenv->init_request();
35$rpcenv->set_language($ENV{LANG});
36$rpcenv->set_user('root@pam');
37
3e16d5fc
DM
38sub extract_archive {
39 # NOTE: this is run as tar subprocess (--to-command)
40
41 $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = $SIG{PIPE} = sub {
42 die "interrupted by signal\n";
43 };
44
45 my $filename = $ENV{TAR_FILENAME};
46 die "got strange environment - no TAR_FILENAME\n" if !$filename;
47
48 my $filesize = $ENV{TAR_SIZE};
49 die "got strange file size '$filesize'\n" if !$filesize;
50
51 my $tmpdir = $ENV{VZDUMP_TMPDIR};
52 die "got strange environment - no VZDUMP_TMPDIR\n" if !$tmpdir;
53
54 my $filetype = $ENV{TAR_FILETYPE} || 'none';
55 die "got strange filetype '$filetype'\n" if $filetype ne 'f';
56
57 my $vmid = $ENV{VZDUMP_VMID};
58 PVE::JSONSchema::pve_verify_vmid($vmid);
59
a0d1b1a2
DM
60 my $user = $ENV{VZDUMP_USER};
61 $rpcenv->check_user_enabled($user);
62
3e16d5fc
DM
63 if ($opts->{info}) {
64 print STDERR "reading archive member '$filename'\n";
65 } else {
66 print STDERR "extracting '$filename' from archive\n";
67 }
68
69 my $conffile = "$tmpdir/qemu-server.conf";
70 my $statfile = "$tmpdir/qmrestore.stat";
71
72 if ($filename eq 'qemu-server.conf') {
73 my $outfd = IO::File->new($conffile, "w") ||
74 die "unable to write file '$conffile'\n";
75
76 while (defined(my $line = <>)) {
77 print $outfd $line;
78 print STDERR "CONFIG: $line" if $opts->{info};
79 }
80
81 $outfd->close();
82
83 exit(0);
84 }
85
86 if ($opts->{info}) {
87 exec 'dd', 'bs=256K', "of=/dev/null";
88 die "couldn't exec dd: $!\n";
89 }
90
91 my $conffd = IO::File->new($conffile, "r") ||
92 die "unable to read file '$conffile'\n";
93
94 my $map;
95 while (defined(my $line = <$conffd>)) {
96 if ($line =~ m/^\#vzdump\#map:(\S+):(\S+):(\d+):(\S*):$/) {
97 $map->{$2} = { virtdev => $1, size => $3, storeid => $4 };
98 }
99 }
100 close($conffd);
101
102 my $statfd = IO::File->new($statfile, "a") ||
103 die "unable to open file '$statfile'\n";
104
105 if ($filename !~ m/^.*\.([^\.]+)$/){
106 die "got strange filename '$filename'\n";
107 }
108 my $format = $1;
109
110 my $path;
111
112 if (!$map) {
113 print STDERR "restoring old style vzdump archive - " .
114 "no device map inside archive\n";
115 die "can't restore old style archive to storage '$opts->{storage}'\n"
a0d1b1a2 116 if defined($opts->{storage}) && $opts->{storage} ne 'local';
3e16d5fc
DM
117
118 my $dir = "/var/lib/vz/images/$vmid";
119 mkpath $dir;
120
121 $path = "$dir/$filename";
122
123 print $statfd "vzdump::$path\n";
124 $statfd->close();
125
126 } else {
127
128 my $info = $map->{$filename};
129 die "no vzdump info for '$filename'\n" if !$info;
130
131 if ($filename !~ m/^vm-disk-$info->{virtdev}\.([^\.]+)$/){
132 die "got strange filename '$filename'\n";
133 }
134
135 if ($filesize != $info->{size}) {
136 die "detected size difference for '$filename' " .
137 "($filesize != $info->{size})\n";
138 }
139
a0d1b1a2
DM
140 # check permission for all used storages
141 my $pool = $opts->{pool};
142 if ($user ne 'root@pam') {
143 if (defined($opts->{storage})) {
144 my $sid = $opts->{storage} || 'local';
fcbb753e 145 $rpcenv->check($user, "/storage/$sid", ['Datastore.AllocateSpace']);
a0d1b1a2
DM
146 } else {
147 foreach my $fn (keys %$map) {
148 my $fi = $map->{$fn};
149 my $sid = $fi->{storeid} || 'local';
fcbb753e 150 $rpcenv->check($user, "/storage/$sid", ['Datastore.AllocateSpace']);
a0d1b1a2
DM
151 }
152 }
153 }
154
3e16d5fc 155 my $storeid;
a0d1b1a2
DM
156 if (defined($opts->{storage})) {
157 $storeid = $opts->{storage} || 'local';
3e16d5fc
DM
158 } else {
159 $storeid = $info->{storeid} || 'local';
160 }
161
162 my $cfg = cfs_read_file('storage.cfg');
163 my $scfg = PVE::Storage::storage_config($cfg, $storeid);
164
445f06cd 165 my $alloc_size = int(($filesize + 1024 - 1)/1024);
3e16d5fc
DM
166 if ($scfg->{type} eq 'dir' || $scfg->{type} eq 'nfs') {
167 # hack: we just alloc a small file (32K) - we overwrite it anyways
168 $alloc_size = 32;
169 } else {
170 die "unable to restore '$filename' to storage '$storeid'\n" .
171 "storage type '$scfg->{type}' does not support format '$format\n"
172 if $format ne 'raw';
173 }
174
175 my $volid = PVE::Storage::vdisk_alloc($cfg, $storeid, $vmid,
176 $format, undef, $alloc_size);
177
178 print STDERR "new volume ID is '$volid'\n";
179
180 print $statfd "vzdump:$info->{virtdev}:$volid\n";
181 $statfd->close();
182
183 $path = PVE::Storage::path($cfg, $volid);
184 }
185
186 print STDERR "restore data to '$path' ($filesize bytes)\n";
187
188 if ($opts->{prealloc} || $format ne 'raw' || (-b $path)) {
189 exec 'dd', 'ibs=256K', 'obs=256K', "of=$path";
190 die "couldn't exec dd: $!\n";
191 } else {
192 exec '/usr/lib/qemu-server/sparsecp', $path;
193 die "couldn't exec sparsecp: $!\n";
194 }
195}
196
197
198if (scalar(@ARGV) == 2) {
199 my $archive = shift;
200 my $vmid = shift;
201
202 # fixme: use API call
203 PVE::JSONSchema::pve_verify_vmid($vmid);
204
205 PVE::Cluster::check_cfs_quorum();
206
a0d1b1a2 207 PVE::QemuServer::restore_archive($archive, $vmid, 'root@pam', $opts);
3e16d5fc
DM
208
209} elsif (scalar(@ARGV) == 0 && $ENV{TAR_FILENAME}) {
210 extract_archive();
211} else {
212 print_usage ();
213 exit(-1);
214}
215
216exit(0);
217
218