+#!/usr/bin/perl -w
+#
+
+use strict;
+use IO::Handle;
+
+my ($passwd,$dashuid,$chown,$phase) = @ARGV;
+my $offset = 20000;
+my $find = "find -xdev";
+
+warn "strips setuid bits!";
+
+our %undomap;
+# construct array mapping
+# new_id -> old_id
+
+my $re = '^(\w[^:]*)\:[^:]+\:(\d+)\:';
+
+sub find_did ($$) {
+ my ($xname,$xid) = @_;
+ # returns the actual uid that source uid xid was (perhaps mistakenly)
+ # mapped to
+ open D, "$passwd-dst" or die $!;
+ while (<D>) {
+ m/$re/o or die "$_ $!";
+ my ($dname,$did) = ($1,$2);
+ return $did if $dname eq $xname;
+ }
+ die $! if D->error;
+ return $xid;
+}
+
+open S, "$passwd-src" or die $!;
+while (<S>) {
+ m/$re/o or die "$_ $!";
+ my ($sname,$sid) = ($1,$2);
+ my $did = find_did($sname,$sid);
+ push @{ $undomap{$did} }, $sid;
+}
+die $! if S->error;
+
+sub mkmap ($$) {
+ my ($in,$out) = @_;
+ printf "$find $dashuid $in -print0 | xargs -0r $chown -- $out\n"
+ or die $!;
+}
+
+our @ambigs;
+
+foreach my $sid (keys %undomap) {
+ my @dids = @{ $undomap{$sid} };
+ next if @dids==1 && $dids[0]==$sid;
+ if ($phase eq '1') {
+ mkmap($sid,$sid+$offset);
+ } elsif ($phase eq '2') {
+ if (@dids==1) {
+ mkmap($sid+$offset,$dids[0]);
+ } else {
+ print "# ambiguous $sid->@dids\n";
+ print "$find $dashuid ".($sid+$offset)." -ls\n"
+ or die $!;
+ }
+ } elsif ($phase eq '0') {
+ next if @dids==1;
+ push @ambigs, $sid;
+ } else {
+ die "$phase ?";
+ }
+}
+
+if ($phase eq '0' && @ambigs) {
+ print "$find \\( ".
+ (join " -o ", map { "$dashuid $_" } @ambigs).
+ " \\) -ls\n"
+ or die $!;
+}
+
+close STDOUT or die $!;