+sub query_loopdev {
+ my ($path) = @_;
+ my $found;
+ my $parser = sub {
+ my $line = shift;
+ if ($line =~ m@^(/dev/loop\d+):@) {
+ $found = $1;
+ }
+ };
+ my $cmd = ['losetup', '--associated', $path];
+ PVE::Tools::run_command($cmd, outfunc => $parser);
+ return $found;
+}
+
+# Run a function with a file attached to a loop device.
+# The loop device is always detached afterwards (or set to autoclear).
+# Returns the loop device.
+sub run_with_loopdev {
+ my ($func, $file) = @_;
+ my $device;
+ my $parser = sub {
+ my $line = shift;
+ if ($line =~ m@^(/dev/loop\d+)$@) {
+ $device = $1;
+ }
+ };
+ PVE::Tools::run_command(['losetup', '--show', '-f', $file], outfunc => $parser);
+ die "failed to setup loop device for $file\n" if !$device;
+ eval { &$func($device); };
+ my $err = $@;
+ PVE::Tools::run_command(['losetup', '-d', $device]);
+ die $err if $err;
+ return $device;
+}
+