return 1;
}
-# Check whether the kernel supports the new mount api. This is used in the pre-start hook and in
-# the hotplugging code.
-my $cached_can_use_new_mount_api = undef;
-sub can_use_new_mount_api() {
- if (!defined($cached_can_use_new_mount_api)) {
- if (PVE::Tools::move_mount(-1, 0, -1, 0, 0)) {
- # This should not be possible...
- die "kernel behaved unexpectedly: move_mount(-1, NULL, -1, NULL) did not fail!\n";
- }
- # On older kernels the syscall doesn't exist and we get ENOSYS. (For newer kernels this call
- # will fail with EFAULT instead, since we pass in a NULL pointer as file system name.)
- $cached_can_use_new_mount_api = ($! != ENOSYS);
- }
- return $cached_can_use_new_mount_api;
-}
-
+ # Tries to the architecture of an executable file based on its ELF header.
+ sub detect_elf_architecture {
+ my ($elf_fn) = @_;
+
+ # see https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
+
+ my $supported_elf_machine = {
+ 0x03 => 'i386',
+ 0x3e => 'amd64',
+ 0x28 => 'armhf',
+ 0xb7 => 'arm64',
+ 0xf3 => 'riscv',
+ };
+
+ my $detect_arch = sub {
+ open(my $fh, "<", $elf_fn) or die "open '$elf_fn' failed: $!\n";
+ binmode($fh);
+
+ my $length = read($fh, my $data, 20) or die "read failed: $!\n";
+
+ # 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");
+
+ my $arch = $supported_elf_machine->{$machine};
+ die "'$elf_fn' has unknown ELF machine '$machine'!\n"
+ if !defined($arch);
+
+ if ($arch eq 'riscv') {
+ if ($class eq 1) {
+ $arch = 'riscv32';
+ } elsif ($class eq 2) {
+ $arch = 'riscv64';
+ } else {
+ die "'$elf_fn' has invalid class '$class'!\n";
+ }
+ }
+
+ return $arch;
+ };
+
+ my $arch = eval { PVE::Tools::run_fork_with_timeout(10, $detect_arch); };
+ my $err = $@ // "timeout\n";
+ die $err if !defined($arch);
+
+ return $arch;
+ }
+
1;