+sub parse_idmap {
+ my ($idmap, $idformat) = @_;
+
+ return undef if !$idmap;
+
+ my $map = {};
+
+ foreach my $entry (PVE::Tools::split_list($idmap)) {
+ if ($entry eq '1') {
+ $map->{identity} = 1;
+ } elsif ($entry =~ m/^([^:]+):([^:]+)$/) {
+ my ($source, $target) = ($1, $2);
+ eval {
+ check_format($idformat, $source, '');
+ check_format($idformat, $target, '');
+ };
+ die "entry '$entry' contains invalid ID - $@\n" if $@;
+
+ die "duplicate mapping for source '$source'\n"
+ if exists $map->{entries}->{$source};
+
+ $map->{entries}->{$source} = $target;
+ } else {
+ eval {
+ check_format($idformat, $entry);
+ };
+ die "entry '$entry' contains invalid ID - $@\n" if $@;
+
+ die "default target ID can only be provided once\n"
+ if exists $map->{default};
+
+ $map->{default} = $entry;
+ }
+ }
+
+ die "identity mapping cannot be combined with other mappings\n"
+ if $map->{identity} && ($map->{default} || exists $map->{entries});
+
+ return $map;
+}
+
+my $verify_idpair = sub {
+ my ($input, $noerr, $format) = @_;
+
+ eval { parse_idmap($input, $format) };
+ if ($@) {
+ return undef if $noerr;
+ die "$@\n";
+ }
+
+ return $input;
+};
+
+# note: this only checks a single list entry
+# when using a storage-pair-list map, you need to pass the full parameter to
+# parse_idmap
+register_format('storage-pair', \&verify_storagepair);
+sub verify_storagepair {
+ my ($storagepair, $noerr) = @_;
+ return $verify_idpair->($storagepair, $noerr, 'pve-storage-id');
+}
+