#!/usr/bin/perl # Copyright (c) 2007 Kari Hurtta # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # if ($#ARGV != 0) { print STDERR "Usage: $0 packager\n"; exit 1; } $packager = $ARGV[0]; use POSIX; $mydir = POSIX::getcwd(); $source_tar = "elm-2.4ME+124.tar.gz"; $decomp = "z"; $basename = "elm-2.4ME+PL124b-1"; $package = "elm"; $version = "2.4ME+PL124b-1"; $prefix = "/usr/local"; $remove = 0; @patch = (); @patch_decomp = (); $patch[0] = "elm-2.4ME+PL124a.patch.gz"; $patch_decomp[0] = "zcat"; $patch[1] = "elm-2.4ME+PL124b.patch.gz"; $patch_decomp[1] = "zcat"; print "Package: $package\n"; print "Version: $version\n"; print "Source: $source_tar\n"; print "Patch: $patch[0]\n"; print "Patch: $patch[1]\n"; $docdir = "$prefix/doc/$basename"; die "$0: No file $source_tar " if (!-f $source_tar); for (my $i = 0; $i <= $#patch; $i++) { die "$0: No file $patch[$i] " if (!-f $patch[$i]); } $source_tar = "$mydir/$source_tar" if $source_tar !~ /^\//; for (my $i = 0; $i <= $#patch; $i++) { $patch[$i] = "$mydir/$patch[$i]" if $patch[$i] !~ /^\//; } @remove = (); sub load_vars ($) { my ($file) = @_; my %my_vars = (); open(CONFIGSH,"<$file") || die "$0: Failed to open $file with error \"$!\" "; while() { next if /^\#/; s/^([^\"\']*)\#/$1/; next if /^\s*$/; while (/^[^\']*\'[^\']*$/s || /^[^\"]*\"[^\"]*$/s) { my $a = ; break if !defined $a; $_ .= $a; } s/\#[^\"\']*$//s; s/\s+$//s; if (/^([^=]+)=\"([^\"]*)\"$/s) { $my_vars{$1}=$2; } elsif (/^([^=]+)=\'([^\']*)\'$/s) { $my_vars{$1}=$2; } elsif (/^([^=]+)=([^\'\"]*)$/s) { $my_vars{$1}=$2; } else { warn "$0: Failed to parse <<$_>> on $file:$. "; } } close(CONFIGSH); return %my_vars; } my $lsb = '/etc/lsb-release'; my $debver = '/etc/debian_version'; $extra=''; if (-f $lsb) { %lsb_vars = load_vars($lsb); if (defined $lsb_vars{'DISTRIB_ID'} && defined $lsb_vars{'DISTRIB_RELEASE'}) { $extra = ".$lsb_vars{'DISTRIB_ID'}$lsb_vars{'DISTRIB_RELEASE'}"; $version .= $extra; print "Version: $version\n"; } } elsif (open(VER,"<$debver")) { # Default to debian if /etc/lsb-release do not exist my $ver1 = ; chomp $ver1; close(VER); if ($ver1 =~ /^\d+(\.\d+)+$/) { $extra = ".Debian$ver1"; $version .= $extra; print "Version: $version\n"; } } $arch=`dpkg --print-architecture`; chomp $arch; print "Arch: $arch\n"; $source_dir = "$mydir/$basename$extra.$arch.source"; $object_dir = ''; if (mkdir $source_dir) { print STDERR "$0: Directory $source_dir created.\n"; push @remove, $source_dir; } $work_dir = "$mydir/$basename$extra.$arch.work"; if (mkdir $work_dir) { print STDERR "$0: Directory $work_dir created.\n"; push @remove, $work_dir; } $control_dir = "$mydir/$basename$extra.$arch.control"; if (mkdir $control_dir) { print STDERR "$0: Directory $control_dir created.\n"; push @remove, $control_dir; } $build_dir = "$mydir/$basename$extra.$arch.build"; if (mkdir $build_dir) { print STDERR "$0: Directory $build_dir created.\n"; push @remove, $build_dir; } # --------------------------------------------------------------------------- sub run_on_children (&) { my ($code) = @_; my $pid = fork(); if (0 == $pid) { my $val = &$code; exit $val; } die "$0: fork failed with error \"$!\" " if (!defined $pid); my $ret = waitpid($pid,0); die "$0: waitpid failed " if ($ret != $pid); die "$0: child died with signal " if ($? & 127); return $? >> 8; } sub cd_system ($@) { my ($dir,@command) = @_; my $ret = run_on_children { chdir $dir || die "$0: cd failed with error \"$!\" "; exec @command; die "$0: $command[0] failed with error \"$!\" "; }; return $ret; } sub cd_system_fail ($@) { my ($dir,@command) = @_; my $ret = cd_system $dir,@command; if ($ret != 0) { warn "$0: Failed to run $command[0] "; exit $ret; } } sub write_config ($$) { my ($file,$content) = @_; open(CONFIG,">$file") || die "$0: Failed to create $file with error \"$!\" "; print CONFIG $content; close(CONFIG) || die "$0: Failed to write $file with error \"$!\" "; } $pid = open (FILELIST,"-|"); die "$0: fork failed with error \"$!\" " if (!defined $pid); if (0 == $pid) { exec 'tar', "t${decomp}f", $source_tar; die "$0: tar failed with error \"$!\" "; } @filelist = ; close FILELIST; if (-1 == $#filelist) { print STDERR "$0: Failed to generate file listing from $source_tar\n"; exit 1; } $first = $filelist[0]; chomp $first; $removefirst = 1; for ($i = 0; $i <= $#filelist; $i++) { $removefirst = 0 if ($filelist[$i] !~ m/^\Q$first\E/); } $first = "" if (! $removefirst); cd_system_fail $source_dir, 'tar', "x${decomp}f", $source_tar; $source_tree = "$source_dir/$first"; for (my $i = 0; $i <= $#patch; $i++) { cd_system_fail $source_tree, "$patch_decomp[$i] $patch[$i] | patch -p1"; } write_config "$source_tree/config.deb",<) { chomp; if (/^\.\/(.*\/elmregister) /) { $elmregister = $1; } if (/package filelist is on +\.\/(.*\/elm\.filelist)/) { $elmfilelist = $1; } } close(README); die "$0: Failed to found elmregister from $readme " if $elmregister eq ''; die "$0: Failed to found elm.filelist from $readme " if $elmfilelist eq ''; $build_list = "$work_dir/filelist.data"; # BINARIES # List aof all files cd_system_fail $build_dir, "$elmregister list -R $build_dir -M all | sort | uniq > $build_list"; open(BUILDLIST,"<$build_list") || die "$0: Failed to open $build_list with error \"$!\" "; $elmrc_write=''; $elmlibregister=''; while() { chomp; if (/^(.*\/elmrc-write)$/) { $elmrc_write=$1; } if (/(.*\/elmlibregister)$/) { $elmlibregister=$1; } } close(BUILDLIST); die "$0: Failed to found elmrc-write from $build_list " if $elmrc_write eq ''; die "$0: Failed to found elmlibregister from $build_list " if $elmlibregister eq ''; # List of files without modules $main_list = "$work_dir/filelist.data.main"; cd_system_fail $build_dir, "$elmregister list -R $build_dir | sort | uniq > $main_list"; # List of directories $dir_list = "$work_dir/filelist.dirs"; cd_system_fail $build_dir, "$elmregister list-directories -R $build_dir -M all | sort | uniq > $dir_list"; %libraries=(); open(LIBLIST,"cat /etc/dpkg/shlibs.override /var/lib/dpkg/info/*.shlibs 2> /dev/null|") || die "$0: Failed to run objdump "; while() { chomp; next if /^\#/; my ($lib,$vers,$deps) = split(/\s+/,$_,3); next if defined $libraries{"$lib.so.$vers"}; $libraries{"$lib.so.$vers"} = $deps; $libraries{"$lib.so"} = $deps if ($vers eq '0'); } close(LIBLIST); # Global seen list %have = (); #temporary list %needed = (); %libneeded = (); sub add_depend ($) { my ($file) = @_; open (OUTPUT,"objdump -p $file 2>/dev/null|") || die "$0: Failed to run objdump "; my %XX = (); my $name = ''; while() { chomp; if (/NEEDED\s+(\S+)$/) { $needed{$1} = 1; $XX{$1} = 1; } if (/SONAME\s+(\S+)$/) { $have{$1} = 1; $name = $1;} } %{ $libneeded{$name} } = %XX if $name ne ''; close(OUTPUT); # Ignoring errors } sub generate_program_required (%) { my ($program) = @_; open (OUTPUT,"dpkg --search $program|") || die "$0: Failed to run dpkg "; my %provides=(); while() { chomp; if (/^(\S+(, \S+)*): .*\Q$program\E$/) { my @a = split(/, /,$1); for my $a ( @a ) { $provides{$a} = 1; } } } close(OUTPUT); # Ignoring errors my $a = join(' | ', keys %provides); print "$program is needed but package do not found\n" if $a eq ''; return $a; } sub generate_required1 (%) { my (%reqs) = @_; my %required = (); for my $soname ( keys %reqs ) { if ($have{$soname}) { next; }; if (defined $libraries{$soname}) { my @a = split(/ *, */,$libraries{$soname}); for my $a (@a) { $required{$a} = 1; } next; } open (OUTPUT,"dpkg --search $soname|") || die "$0: Failed to run dpkg "; my %provides=(); while() { chomp; if (/^(\S+(, \S+)*): .*\b\Q$soname\E$/) { my @a = split(/, /,$1); for my $a ( @a ) { $provides{$a} = 1; } } } close(OUTPUT); # Ignoring errors my $a = join(' | ', keys %provides); $required{$a} = 1 if $a ne ''; print "$soname is needed but package do not found\n" if $a eq ''; } return %required; } sub generate_required ($) { my ($list) = @_; # Reset needed module list %needed = (); open(MAINLIST,"<$list") || die "$0: Failed to open $list with error \"$!\" "; while(my $file = ) { chomp $file; if (-x "$build_dir/$file" || $file =~ /\/lib.*\.so/) { add_depend("$build_dir/$file"); } } close(MAINLIST); my %required = generate_required1 %needed; return %required; } %required_modules = generate_required($main_list); %suggested_modules = (); %tmp = generate_required($build_list); for my $a ( keys %tmp ) { if (defined $required_modules{$a}) { next; }; $suggested_modules{$a} = 1; } sub add_suggested_prog ($) { my ($var) = @_; if ($vars{$var} ne '') { return if $vars{$var} eq 'none'; return if $vars{$var} =~ /builtin/; my $link = readlink($vars{$var}); my $a; if ($link =~ m/^\/etc\/alternatives/) { print "$vars{$var} is link to $link\n"; # But we can suggest real program here ... my $X1 = readlink $link; return if $X1 eq ''; $a = generate_program_required($X1); } else { $a = generate_program_required($vars{$var}); } if ($a ne '') { $suggested_modules{$a} = 1 if ! defined $required_modules{$a}; } } else { print "Variable $var not found\n"; } } add_suggested_prog 'gpg_path'; add_suggested_prog 'pgp'; add_suggested_prog 'mailer'; add_suggested_prog 'pager'; add_suggested_prog 'defeditor'; add_suggested_prog 'emacs'; add_suggested_prog 'vi'; add_suggested_prog 'linepr'; add_suggested_prog 'metamail_path'; $XXelmfilelist = "$elmfilelist.gen-deb.$basename"; @build_files = ( $XXelmfilelist ); rename("$build_dir/$elmfilelist","$build_dir/$XXelmfilelist") || die "$0: Failed to rename $build_dir/$elmfilelist => $build_dir/$XXelmfilelist with error \"$!\" "; # DOCUMENTS cd_system_fail $build_dir, 'mkdir', '-p', "./$docdir"; @docdirlist=( $docdir ); sub install_doc ($) { my ($file) = @_; cd_system_fail $source_tree, 'install', '-m', '644', $file, "$build_dir/$docdir/$file"; my $A = "$docdir/$file"; $A =~ s/^\/+//; push(@build_files, $A); } sub install_docdir ($) { my ($file) = @_; $file = "$docdir/$file"; $file =~ s/^\/+//; cd_system_fail $build_dir, 'mkdir', '-p', $file; push(@docdirlist,$file); } install_doc "README.ME+"; install_doc "NOTICE"; install_doc "MIME.txt"; install_doc "Overview"; install_doc "ANNOUNCE.ME"; install_doc "ChangeLog.ME"; install_doc "Patchlist"; install_doc "Changes"; install_doc "Instruct"; install_doc "NOTICE"; install_doc "README"; install_docdir "doc"; install_doc "doc/elmrc.samp"; install_doc "doc/mime.charsets"; install_doc "doc/mime.types"; install_doc "doc/terminal.info"; install_docdir "shared_libs/tls"; install_doc "shared_libs/tls/README.ME+"; install_docdir "shared_libs/iconv"; install_doc "shared_libs/iconv/README.ME+"; install_docdir "shared_libs/smtp"; install_doc "shared_libs/smtp/README.ME+"; cd_system_fail $build_dir, 'tar', 'czf', "$work_dir/data.tar.gz", '--owner=0', '--group=0', "--files-from=$build_list", @build_files; # CONFIG FILES @config_files = (); $depends = join(', ', keys %required_modules); $suggest = join(', ', keys %suggested_modules); sub write_config_file ($$) { my ($file,$content) = @_; write_config "$control_dir/$file", $content; push(@config_files,$file); } sub write_config_script ($$) { my ($file,$content) = @_; write_config_file $file,$content; chmod 0755,"$control_dir/file" || die "chmod for $control_dir/file with error \"$!\" "; } write_config_file "control",<) { chomp; $commands .= "mkdir -p \"/$_\"\n"; } close(DIRLIST); for (@docdirlist) { $commands .= "mkdir -p \"/$_\"\n"; } $XXshlib=''; if ($vars{'shlib'} ne '') { $XXshlib=<> /$elmfilelist rm /$XXelmfilelist /$elmregister unstage || true if [ ! -f $vars{'etc'}/elm.rc.debsave ] then cat <<'EOX' ============================================================= Edit $vars{'etc'}/elm.rc configuration file and specify on mailer= line capabilites of $vars{'mailer'}. Default value of this line is printed with $vars{'bin'}/elm -vvv command. ============================================================= EOX fi exit \$err ;; abort-remove) echo "\$0: abort-remove is not possible" exit 1 ;; abort-upgrade|abort-deconfigure) err=0 F=$vars{'etc'}/elm.rc.old-values if [ -f \$F ] ; then /$elmrc_write -IG \$F || true fi /$elmrc_write -IG -c \$F || err=\$? /$elmlibregister -IG -c \$F || err=\$? /$elmregister unstage || true exit \$err ;; esac exit 0 EOM ; write_config_script "prerm",<