use warnings;
use File::Basename;
use File::Path;
-use Data::Dumper;
use Fcntl;
use PVE::Storage;
sub detect_architecture {
my ($rootdir) = @_;
- my $supported_elf_class = {
- 1 => 'i386',
- 2 => 'amd64',
+ # see https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
+
+ my $supported_elf_machine = {
+ 0x03 => 'i386',
+ 0x3e => 'amd64',
+ 0x28 => 'armhf',
+ 0xb7 => 'arm64',
};
my $elf_fn = '/bin/sh'; # '/bin/sh' is POSIX mandatory
open(my $fh, "<", $elf_fn) or die "open '$elf_fn' failed: $!\n";
binmode($fh);
- my $length = read($fh, my $data, 5) or die "read failed: $!\n";
+ my $length = read($fh, my $data, 20) or die "read failed: $!\n";
- # 4 bytes ELF magic number and 1 byte ELF class
- my ($magic, $class) = unpack("A4C", $data);
+ # 4 bytes ELF magic number and 1 byte ELF class, padding, machine
+ my ($magic, $class, undef, $machine) = unpack("A4CA12n", $data);
die "'$elf_fn' does not resolve to an ELF!\n"
if (!defined($class) || !defined($magic) || $magic ne "\177ELF");
- die "'$elf_fn' has unknown ELF class '$class'!\n"
- if !defined($supported_elf_class->{$class});
+ my $arch = $supported_elf_machine->{$machine};
+ die "'$elf_fn' has unknown ELF machine '$machine'!\n"
+ if !defined($arch);
- return $supported_elf_class->{$class};
+ return $arch;
};
my $arch = eval { PVE::Tools::run_fork_with_timeout(5, $detect_arch) };
'.gz' => '-z',
'.bz2' => '-j',
'.xz' => '-J',
+ '.lzo' => '--lzop',
);
if ($archive =~ /\.tar(\.[^.]+)?$/) {
if (defined($1)) {
- @compression_opt = $compression_map{$1}
- or die "unrecognized compression format: $1\n";
+ die "unrecognized compression format: $1\n" if !defined($compression_map{$1});
+ @compression_opt = $compression_map{$1};
}
} else {
die "file does not look like a template archive: $archive\n";
$conf = PVE::LXC::Config::parse_pct_config("/lxc/0.conf" , $raw);
delete $conf->{snapshots};
- delete $conf->{template}; # restored CT is never a template
PVE::LXC::Config->foreach_mountpoint($conf, sub {
my ($ms, $mountpoint) = @_;
}
sub restore_configuration {
- my ($vmid, $rootdir, $conf, $restricted) = @_;
+ my ($vmid, $rootdir, $conf, $restricted, $unique, $skip_fw) = @_;
# restore: try to extract configuration from archive
next if $key eq 'digest' || $key eq 'rootfs' || $key eq 'snapshots' || $key eq 'unprivileged' || $key eq 'parent';
next if $key =~ /^mp\d+$/; # don't recover mountpoints
next if $key =~ /^unused\d+$/; # don't recover unused disks
- if ($restricted && $key eq 'lxc') {
- warn "skipping custom lxc options, restore manually as root:\n";
- warn "--------------------------------\n";
+ # we know if it was a template in the restore API call and check if the target
+ # storage supports creating a template there
+ next if $key =~ /^template$/;
+
+ if ($key eq 'lxc') {
my $lxc_list = $oldconf->{'lxc'};
- foreach my $lxc_opt (@$lxc_list) {
- warn "$lxc_opt->[0]: $lxc_opt->[1]\n"
+ if ($restricted) {
+ warn "skipping custom lxc options, restore manually as root:\n";
+ warn "--------------------------------\n";
+ foreach my $lxc_opt (@$lxc_list) {
+ warn "$lxc_opt->[0]: $lxc_opt->[1]\n"
+ }
+ warn "--------------------------------\n";
+ } else {
+ @{$conf->{$key}} = (@$lxc_list, @{$conf->{$key}});
}
- warn "--------------------------------\n";
+ next;
+ }
+
+ if ($unique && $key =~ /^net\d+$/) {
+ my $net = PVE::LXC::Config->parse_lxc_network($oldconf->{$key});
+ my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
+ $net->{hwaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix});
+ $conf->{$key} = PVE::LXC::Config->print_lxc_network($net);
next;
}
$conf->{$key} = $oldconf->{$key} if !defined($conf->{$key});
}
unlink($pct_cfg_fn);
- if (-f $pct_fwcfg_fn) {
+ # note: this file is possibly from the container itself in backups
+ # created prior to pve-container 2.0-40 (PVE 5.x) / 3.0-5 (PVE 6.x)
+ # only copy non-empty, non-symlink files, and only if the user is
+ # allowed to modify the firewall config anyways
+ if (-f $pct_fwcfg_fn && ! -l $pct_fwcfg_fn && -s $pct_fwcfg_fn) {
my $pve_firewall_dir = '/etc/pve/firewall';
- mkdir $pve_firewall_dir; # make sure the directory exists
- PVE::Tools::file_copy($pct_fwcfg_fn, "${pve_firewall_dir}/$vmid.fw");
+ my $pct_fwcfg_target = "${pve_firewall_dir}/${vmid}.fw";
+ if ($skip_fw) {
+ warn "ignoring firewall config from backup archive's '$pct_fwcfg_fn', lacking API permission to modify firewall.\n";
+ warn "old firewall configuration in '$pct_fwcfg_target' left in place!\n"
+ if -e $pct_fwcfg_target;
+ } else {
+ mkdir $pve_firewall_dir; # make sure the directory exists
+ PVE::Tools::file_copy($pct_fwcfg_fn, $pct_fwcfg_target);
+ }
unlink $pct_fwcfg_fn;
}