Child pages
  • Building an IPS manifest

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Moved script from inline to an attachment

...

Code Block
perl dir2manifest.pl usr > ../payload

Here's the script:

Code Block
#!/usr/bin/perl -w

# Scan a directory tree and output manifest information that can be passed
# to pkgsend include
#
# Currently this just detects directories, files, hardlinks and symlinks.

use strict;
use File::Spec;

my $dir = shift || die "usage: $0 dir\n";

if ($dir =~ m{^/}) {
    $dir =~ s{^/}{};
    chdir "/";
}

# Calculate the relative path from src to dst
# File::Spec->abs2rel($dstfile, $srcdir)
sub relativepath {
    my (@src) = File::Spec->splitdir(shift);
    my $dstfile = shift;
    pop @src;
    my $srcdir = File::Spec->catdir(@src);
    return File::Spec->abs2rel($dstfile, $srcdir);
}

my @dirs;
my @files;
my @links;
my @symlinks;

# Core directories - ideally we should depend on some package
# that provides these, but that package doesn't exist right now.
# Until then just make sure they are root:sys instead of root:bin
my %coredir;
foreach my $f qw(usr usr/share usr/gnu/share opt etc) { $coredir{$f} = 1; }
open FIND, "find -H $dir -type d -print|";
while (<FIND>) {
    chomp;
    if (exists $coredir{$_}) {
	push @dirs, "dir mode=0755 owner=root group=sys path=$_";
    } else {
	push @dirs, "dir mode=0755 owner=root group=bin path=$_";
    }
}
close FIND or die "$0: error running find:$!";

# Indexed by inode, this lets us detect and recreate hard linked files
my %installed;
open FIND, "find -H $dir -type f -print|";
while (<FIND>) {
    chomp;
    next if  m{(^|/)(\.packlist|perllocal.pod)$};
    my ($inode) = (stat $_)[1];
    if (exists $installed{$inode}) {
	my $target = relativepath($_, $installed{$inode});
	push @links, "hardlink path=$_ target=$target";
    } else {
	my $mode = '0444';
	if (-x $_) {
	    $mode = '0555';
	} else {
	    # There must be a better way than running file(1)
	    my $t = `file $_`;
	    $mode = '0555' if $t =~ m{:\tELF};
	}
	push @files, "file $_ mode=$mode owner=root group=bin path=$_";
	$installed{$inode} = $_;
    }
}
close FIND or die "$0: error running find:$!";

open FIND, "find -H $dir -type l -print|";
while (<FIND>) {
    chomp;
    my $target = relativepath($_, readlink $_);
    push @symlinks, "link path=$_ target=$target";
}
close FIND or die "$0: error running find:$!";

# TODO: look for other installable things

print join "\n", @dirs, (sort @files), (sort @links), (sort @symlinks), '';

5. Join "metadata", "deps", and "payload" together into "manifest":

...