While we don't know the state of pobj in portcheck, here in
portgen we can assume that it's freshly extracted and so whatever
permissions are on the files came from the archive.

It was pointed out by cwen@ that with PORTS_PRIVSEP=Yes, portgen fails
to update devel/p5-Moose because of the permission to the extracted
files and that we could detect that, set FIX_EXTRACT_PERMISSIONS and
then clean and re-extract to be able to continue.

It isn't entirely true that we know the state, because if you cancel a
portgen run partway through and rm -r /usr/ports/mystuff there is cruft
still in /usr/ports/pobj another run will find the old WRKSRC from the
previous run, which had FIX_EXTRACT_PERMISSIONS applied, so this check
now succeeds and we don't reset it the next time through.  We could add
a $self->make_clean just before the other $self->make_extract, but is it
would slow things down slightly.

(Sadly File::Find doesn't have a "stop finding" feature, so we just have
to stop checking and prune to avoid possible permission failures inside
a directory)

Thoughts? OK?


Index: lib/OpenBSD/PortGen/Port.pm
===================================================================
RCS file: /cvs/ports/infrastructure/lib/OpenBSD/PortGen/Port.pm,v
retrieving revision 1.18
diff -u -p -r1.18 Port.pm
--- lib/OpenBSD/PortGen/Port.pm 12 Jun 2019 19:25:53 -0000      1.18
+++ lib/OpenBSD/PortGen/Port.pm 23 Nov 2019 21:54:24 -0000
@@ -21,6 +21,8 @@ use 5.012;
 use warnings;
 
 use Cwd;
+use Fcntl qw( :mode );
+use File::Find qw();
 use File::Path qw( make_path );
 use JSON::PP;
 use Text::Wrap;
@@ -222,6 +224,37 @@ sub set_test_deps
        $self->{TEST_DEPENDS} = $test_deps;
 }
 
+sub set_fix_extract_permissions
+{
+       my ($self, $value) = @_;
+
+       return $self->{FIX_EXTRACT_PERMISSIONS} = $value
+           if @_ == 2;
+
+       my $perm_file = S_IRUSR | S_IRGRP | S_IROTH;
+       my $perm_dir  = S_IXUSR | S_IXGRP | S_IXOTH | $perm_file;
+
+       # Assume a cached stat on whatever mode we are checking
+       my $perm_ok = sub {
+               my $mode = ( stat _ )[2];
+               return S_ISDIR($mode)
+                   ? ($mode & $perm_dir ) == $perm_dir
+                   : ($mode & $perm_file) == $perm_file;
+       };
+
+       my $wrksrc = $self->make_show('WRKSRC');
+
+       # Look through WRKSRC for files that don't have
+       # the necessary permissions.
+       my $needs_fix;
+       File::Find::find({ no_chdir => 1, wanted => sub {
+               $needs_fix = $File::Find::prune = 1
+                   if $needs_fix or not $perm_ok->();
+       } }, $wrksrc );
+
+       return $self->{FIX_EXTRACT_PERMISSIONS} = $needs_fix ? 'Yes' : undef;
+}
+
 sub set_other
 {
        my ( $self, $var, $value ) = @_;
@@ -536,6 +569,12 @@ sub make_port
        $self->make_makesum();
        $self->make_checksum();
        $self->make_extract();
+
+       if ( $self->set_fix_extract_permissions() ) {
+               $self->write_makefile();
+               $self->make_clean();
+               $self->make_extract();
+       }
 
        my $wrksrc = $self->make_show('WRKSRC');
 

Reply via email to