package Mkcd::Tools; our $VERSION = '0.5.4'; use strict; use File::NCopy qw(copy); use Image::Size qw(:all); use Mkcd::Commandline qw(parseCommandLine usage); use Digest::MD5; require Exporter; use URPM; our @ISA = qw(Exporter); our @EXPORT = qw(printTable getTracks du cpal checkcds checkDiscs cleanrpmsrate imageSize printDiscsFile readBatchFile printBatchFile config compute_md5 log_ include_md5); our $INFO_OFFSET = 883; our $SIZE_OFFSET = 84; our $SKIP = 15; =head1 NAME tools - mkcd tools =head1 SYNOPSYS require mkcd::tools; =head1 DESCRIPTION includes mkcd tools. =head1 SEE ALSO mkcd =head1 COPYRIGHT Copyright (C) 2000,2001 MandrakeSoft This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. =head1 CREDITS md5 code highly inspired from Redhat anaconda md5 in ISO code =cut sub printTable { my ($a,$log) = @_; my $LOG; if ($log) { my $LOG = $log } else { open $LOG, ">&STDERR" } # # iterative version of a recursive scanning of a table. # ex: @config = [[[1,3],3,[1,3,[1,3]]],3,4,[4,[4,4]]] # my @A; my @i; my @tab; my $i = 0; while ($a){ my $u = ref $a; if ($u eq 'ARRAY') { while ($i < @$a){ my $b = $a->[$i]; my $t = ref $b; if ($t eq 'ARRAY'){ push @tab, "\t"; push @i, $i+1; push @A, $a; $i = 0; $a = $b; next } elsif ($t eq 'HASH') { $i++; print $LOG "@tab", join ' ',keys %$b,"\n" } else { $i++; print $LOG "@tab$b\n" } } } else { print $LOG "$a\n" } pop @tab; $i = pop @i; $a = pop @A; } } sub getTracks{ my ($tracks,$log) = @_; my $LOG; if ($log) { my $LOG = $log } else { open $LOG, ">&STDERR" } my @tracks = split ',',$tracks; my @t; foreach (@tracks){ /(\d+)/ and push @t, $1; /(\d+)-(\d+)/ and push @t, $1..$2 } my @ntracks; my %done; for (my $i = $#t; $i >= 0; $i--){ push @ntracks, $t[$i] if !$done{$t[$i]}; $done{$t[$i]}=1 } \@ntracks; } sub du { my ($path,$size) = @_; if (-d $path){ opendir O, $path; foreach (readdir O){ /^\.{1,2}$/ and next; -l "$path/$_" or $size += du("$path/$_") } } else { -l $path or $size = (stat $path)[7] + 2048; } $size } sub cpal{ my ($source,$dest,$exclude,$verbose,$log) = @_; my $LOG; if ($log) { my $LOG = $log } else { open $LOG, ">&STDERR" } if ($exclude && "$source/$_" =~ /$exclude/) { return 0 } if (!-l $source && -d $source){ mkdir "$dest"; opendir O, $source; foreach (readdir O){ /^\.{1,2}$/ and next; cpal("$source/$_","$dest/$_",$exclude,$verbose) } }else { my $err; if (-d $dest){ my ($filename) = $source =~ /([^\/]*)$/; $dest .= "/$filename" } $err = link "$source","$dest" ; $verbose and print $LOG "cpal: link $source -> $dest\n" ; if (!$err) { print $LOG "Linking failed $source -> $dest: $!, trying to copy\n" ; $err = copy "$source", "$dest"; if (!$err) { print $LOG "Copying failed $source -> $dest: $!,\n"; return 0 } } } 1 } sub checkDiscs{ my ($hdlists,$depslist,$discsFiles,$check,$log) = @_; my $LOG; if ($log) { $LOG = $log } else { open $LOG, ">&STDOUT" } local *A; open A, $depslist or print $LOG "ERROR: unable to open $depslist" and return 0; # # depslist hdlist consistency -> error ok (not the same as instal one, but duplicate will break anyway) # # in hdlist, not in depslist -> error ok # # in hdlist, not in dir -> error ok # # in hdlist with packdrake, no with parsehdlist -> error # # in depslist, not in hdlist -> error ok # # in depslist, not in dir -> error ok # # in dir, not in hdlist -> warning ok # # in dir, not in depslist -> warning ok # # multiple version in depslist -> error ok # # multiple version in hdlist -> error ok # # multiple in dir -> warning ok # my $ok = 1; my $OK = 1; my %depslist; my %depslistname; my $i = 1; print $LOG "checkDiscs: duplicate version in $depslist:"; while (){ my ($pkg,$name) = ((split)[0]) =~ /((.*)-[^-]+-[^-]+\.[^:]+)/; $depslist{$pkg} and do { print $LOG "\n$pkg"; $ok = 0 }; $depslistname{$name} and do { print $LOG "\n$name"; $ok = 0 }; $depslist{$pkg} = $i; $depslistname{$name} = $i++; } close A; $ok or $OK = 0; $ok ? print $LOG " OK\n" : print $LOG "\nFAILED\n"; my %hdlist; print $LOG "\ncheckDiscs: duplicate version in hdlists:"; my $maxidx; my %rpm; my (@rnh,@hnd,@duprep,@rnd,@hnr,%rpmKeys,%parsehdlist,@pnh,@hnp); $ok = 1; my $parsehdlist; my $path = $0; $path =~ s/[^\/]*$//; if (-x "$path/parsehdlist"){ $parsehdlist = "$path/parsehdlist" } elsif (-x "/usr/bin/parsehdlist"){ $parsehdlist = "/usr/bin/parsehdlist" } else { my $err = system('parsehdlist'); if ($err){ $parsehdlist = "parsehdlist" } else { print $LOG, "ERROR checkDiscs: could not find parsehdlist command ($!)\n"; return 0 } } for (my $i = 1; $i < @$hdlists; $i++){ if (! -f $hdlists->[$i]) { print $LOG "\nWARNING checkDiscs: $hdlists->[$i] is empty, ignoring\n"; next } my $packer = new packdrake($hdlists->[$i]); my $j; foreach my $file (@{$packer->{files}}) { my ($rpm,$key) = $file =~ /([^:]*)(?::(.*))?/; $rpmKeys{key}{$rpm} = $key ? $key : $rpm; $rpmKeys{rpm}{$rpmKeys{key}{$rpm}} = $rpm; my $sok; foreach my $c (@{$check->[$i]}){ my ($cd,$rep,$list) = @$c; $discsFiles->[$cd]{$rep}{$list}{$rpmKeys{key}{$rpm}} and $sok = 1; } $sok or push @hnr, [ $i, $rpm ]; $depslist{$rpm} or push @hnd, $rpm; $hdlist{all}{$rpm} and do { print $LOG "\n$rpm"; $ok = 0 }; $hdlist{all}{$rpm} = 1; $hdlist{cd}{$i}{$rpm} = 1; $depslist{$rpm} > $j and $j = $depslist{$rpm}; $depslist{$rpm} < $maxidx and print $LOG "ERROR checkDiscs: inconsistency in position between hdlist $i rpm $rpm and depslist.ordered\n" } foreach my $c (@{$check->[$i]}){ my ($cd,$rep,$list) = @$c; foreach my $rpm (keys %{$discsFiles->[$cd]{$rep}{$list}}){ $rpm{$rpmKeys{rpm}{$rpm}} and push @duprep, $rpm; $rpm{$rpmKeys{rpm}{$rpm}} = 1; $depslist{$rpmKeys{rpm}{$rpm}} or push @rnd, [ $i, $cd, $rep, $rpm ]; $hdlist{cd}{$i}{$rpmKeys{rpm}{$rpm}} or push @rnh, [ $i, $rpm ] } } local *PAR; open PAR, "$parsehdlist $hdlists->[$i] |"; while (){ chomp; s/\.rpm$//; $parsehdlist{$i}{$_} = 1; $hdlist{cd}{$i}{$_} and next; push @pnh, $_ } foreach my $p (keys %{$hdlist{cd}{$i}}){ $parsehdlist{$i}{$p} or push @hnp, $p } $maxidx = $j; } $ok or $OK = 0; $ok ? print $LOG " OK\n" : print $LOG "\nFAILED\n"; my @dnh; $ok = 1; print $LOG "\ncheckDiscs: in depslist, not on discs:"; foreach my $rpm (keys %depslist){ $hdlist{all}{$rpm} or do { push @dnh, $rpm }; $rpm{$rpm} or do { $ok = 0; print $LOG "\n$rpm" }; } $ok or $OK = 0; $ok ? print $LOG " OK\n" : print $LOG "\nFAILED\n"; print $LOG "\ncheckDiscs: in depslist, not in hdlists:"; @dnh ? do { print $LOG " FAILED\n" and $OK = 0 } : print $LOG " OK\n"; foreach (@dnh){ print $LOG "$_\n" } print $LOG "\ncheckDiscs: in hdlists, not on discs:"; @hnr ? do { print $LOG " FAILED\n" and $OK = 0 } : print $LOG " OK\n"; foreach (@hnr){ print $LOG "hdlist $_->[0] rpm $_->[3]\n" } print $LOG "\ncheckDiscs: in hdlists, not in depslist:"; @hnd ? do { print $LOG " FAILED\n" and $OK = 0 } : print $LOG " OK\n"; foreach (@hnd){ print $LOG "$_\n" } print $LOG "\ncheckDiscs: in hdlists, not see with parsehdlist:"; @hnp ? do { print $LOG " FAILED\n" and $OK = 0 } : print $LOG " OK\n"; foreach (@hnp){ print $LOG "$_\n" } print $LOG "\ncheckDiscs: see with parsehdlist, not with packdrake:"; @pnh ? do { print $LOG " FAILED\n" and $OK = 0 } : print $LOG " OK\n"; foreach (@pnh){ print $LOG "$_\n" } print $LOG "\ncheckDiscs: on discs, not in hdlist:"; @rnh ? print $LOG " WARNING\n": print $LOG " OK\n"; foreach (@rnh){ print $LOG "hdlist $_->[0] rpm $_->[1]\n" } print $LOG "\ncheckDiscs: on discs, not in depslist:"; @rnd ? print $LOG " WARNING\n": print $LOG " OK\n"; foreach (@rnd){ print $LOG "hdlist $_->[0] cd $_->[1] rep $_->[2] missing rpm $_->[3]\n" } print $LOG "\ncheckDiscs: duplicate version on discs:"; @duprep ? print $LOG " WARNING\n": print $LOG " OK\n"; foreach (@duprep){ print $LOG "$_\n" } return $OK } # # check depslist, depslists.ordered and hdlists # sub checkcds{ my (@tops) = @_; my $top = "$tops[0]/"; my $depslist = "$tops[0]/Mandrake/base/depslist.ordered"; -f $depslist or print "ERROR: could not find depslist $depslist file\n" and return 0; my $hdlists = "$top/Mandrake/base/hdlists"; local *A; open A, $hdlists or die "unable to open $hdlists"; my @hdlist = (0); my @discsFiles; my @check = (0); while (){ my ($hdlist, $dir, undef) = split; my ($hdid) = $hdlist =~ /(\d*).cz/; my $hdfile = "$tops[0]/Mandrake/base/$hdlist"; push @hdlist, $hdfile; push @check, [[ $hdid, $dir, 1 ]]; -f $hdfile or print "ERROR: could not find $hdfile file\n" and return 0; local *C; if (! opendir C, "$top/$dir"){ foreach (@tops){ opendir C, "$_/$dir" or next; last } } foreach (readdir C){ /(.*)\.rpm/ or next; $discsFiles[$hdid]{$dir}{1}{$1} = 1 } } checkDiscs(\@hdlist,$depslist,\@discsFiles,\@check) } # # regexp version # sub cleanrpmsrate2 { my ($rpmsrate,@rpms) = @_; my $LOG; open $LOG, ">&STDERR"; my @rpm; foreach (@rpms){ -d or print $LOG "ERROR: $_ is not a directory\n" and next; local *A; opendir A, $_; push @rpm, grep { s/-[^-]+-[^-]+\.[^.]+\.rpm// } readdir A; } my %done; my (@flags,@c); my ($mod,$text,$prev,$rate,$current); my (%rate,%section); local *A; open A, $rpmsrate or print $LOG "ERROR: cannot open $rpmsrate\n"; while (){ s/#.*//; /^\s*$/ and $text .= "\n" and next; if (/^(\S+)/) { $text .= "$1\n"; $current = $1; @flags = ($current); next } my ($indent,$r,$flags,$data) = /^(\s*)([1-5]?)((?:\s+(?:(?:!\s*)?[0-9A-Z_]+(?:"[^"]*")?(?:\s+(?:\|\|\s+)?)*)+\s+)|\s+)(.*)$/; if ($r) { $rate = $r }elsif ($prev){ chop $indent; $r = $prev } push @flags, split ' ', $flags; $data or $text .= "$indent$r$flags" and next; my ($postfix) = $data =~ /(\s*)$/; my @k; foreach my $n (split ' ', $data) { @c = grep { /^$n$/ } @rpm; map { if ((!$done{$_}[1] || $current eq "INSTALL") && $done{$_}[0] ne $current) { push @k, $_; @{$done{$_}} = @flags } } @c } if (@k) { $text .= "$indent$r$flags@k$postfix\n"; $prev = '' } else { $prev = $r }; @rate{@k} = ($rate) x @k; push @{$section{$current}}, @k } close A; if (@rpms){ if (open A, ">$rpmsrate") { print A $text; close A }else{ @rpms and print $LOG "ERROR: cannot open $rpmsrate for writing\n"; print $text } } [\%rate,\%section]; } sub cleanrpmsrate { my ($rpmsrate,$output,$norpmsrate,$reprpms) = @_; $norpmsrate ||= []; my $LOG; open $LOG, ">&STDERR"; local *A; open A, $rpmsrate or print $LOG "ERROR: cannot open $rpmsrate\n"; my (@rpmsrate, %potloc); # must preread to get locale guessed packages # postfix is just used not to break the diff when checking if the result is correct while (){ chomp; s/#.*//; #s/\s*$//; /^(\s*)$/ and push @rpmsrate, [ '', 0, '', []] and next; if (/^(\S+)(.*)$/) { push @rpmsrate, [ 0, 0, $1, [], $2]; next } if (/^(\s*)([1-5])?(\s?[0-9A-Z_]+)$/) { push @rpmsrate, [ $1, $2, $3, []]; next } my ($indent,$r,$flags,$data) = /^(\s*)([1-5])?(\s*(?:(?:(?:!\s*)?[0-9A-Z_]+(?:"[^"]*")?(?:\s+(?:\|\|\s+)?)*)+\s+)|\s*)(.*)$/; my ($postfix) = $data =~ /(\s*)$/; my @data; my $i; foreach ([$data =~ /(?:^|\s)(\S+)-(?:\S+)\s+\1-(?:\S+)(?:\s|$)/g],[split ' ', $data]){ $data[$i++] = [ @$norpmsrate ? grep { my $r = $_; $r if (!grep { $r =~ /$_/ } @$norpmsrate) } @$_ : @$_ ] } map $potloc{$_} = [], @{$data[0]}; push @rpmsrate, [ $indent,$r, $flags, $data[1], $postfix ]; } my (%rpms,$text); my (%rate,%section); my (%locale,%localized_pkg); foreach my $dir (keys %$reprpms){ foreach (@{$reprpms->{$dir}}) { my $rpm = "$_.rpm"; s/-[^-]+-[^-]+\.[^.]+$// or next; grep { $rpm =~ /$_/ } @$norpmsrate and next; if (/(.*?)([_-]*[\d._]*)-devel$/ || /(kernel.*)(-[^.]+\.[^.]+\.[^.]+\.[^.]+mdk)$/){ if (!$rpms{$1}){ $rpms{$1} = $2 } elsif (URPM::ranges_overlap("== $2","> $rpms{$1}")){ $rpms{$1} = $2 } }elsif (my ($pg,$loc) = /^(.*)-([^-+]+)$/){ if ($potloc{$pg}){ my %header; tie %header, "RPM::Header", "$dir/$rpm" or print "ERROR: $RPM::err\n" and next; if (grep { s/locales-// && $loc =~ /^$_(_|$)/ } @{$header{REQUIRENAME}}) { push @{$locale{$pg}}, $loc; $localized_pkg{"$pg-$loc"} = 1 } } } } } my (%done,@flags,$prev,@tree_rate,$prev_level); foreach (@rpmsrate){ if (!$_->[0]){ $text .= "$_->[2]$_->[4]\n"; if ($_->[2]){ @flags = ($_->[2]) } next } my ($indent,$r,$flags,$data,$postfix) = @$_; my $level = (length $indent)/2 - 1; my $rate; if ($r) { #print "tree_rate[$level] = $r\n"; $rate = $r; $tree_rate[$level] = $r }else{ if (@$data) { if ($level > $prev_level) { $level-- } else { # fix a syntax error in rpmsrate such as # A # 1 toto # B tata <--- # 4 titi @$data = () } } $rate = $tree_rate[$level]; } $prev_level = $level; @flags = @flags[0 .. $level]; push @flags, grep { s/\s//; !/(\|\||[A-Z_]+\"[^"]+\")/ } split(' ', $flags); my $flat_path = join ' ', @flags; if (!@$data) { $text .= "$indent$r$flags$postfix\n"; next } my @k; foreach (@$data) { my $c = $_; if ($done{$_} eq $flat_path) { next } my ($d) = /(.*)-[^-]+/; my ($a,$b); if (((($flags[0] ne "INSTALL") && (s/(-devel)//)) ? $b = "-devel" : /^kernel/) && ($rpms{$_} || ($rpms{"lib$_" } and $a = "lib"))) { my $d = "$a$_" . $rpms{"$a$_" } . "$b"; if (!$done{$d} || $flags[0] eq "INSTALL") { $done{$d} = $flat_path; push @k, $d } } if ($locale{$d} && $localized_pkg{$c}){ foreach (sort @{$locale{$d}}){ next if $done{"$d-$_"} eq $flat_path; $done{"$d-$_"} = $flat_path; push @k ,"$d-$_" } next } push @k, $c; $done{$c} = $flat_path } if (@k) { $text .= "$indent$r$flags@k$postfix\n" } @rate{@k} = ($rate) x @k; my $path; foreach (@flags){ $path .= $path ? "/$_" : "$_"; push @{$section{$path}}, @k } } if (%rpms || $output){ if (%$reprpms || $output){ $output ||= $rpmsrate; if (open A, ">$output") { print A $text; close A } else { print $LOG "ERROR cleanrpmsrate: cannot open $rpmsrate for writing\n"; print $text } } } [\%rate,\%section]; } sub imageSize { my ($file) = @_; my ($width, $height, $err) = imgsize $file; return ((defined $width) ? [ $width, $height ] : "error: $err") } sub printDiscsFile{ my ($config,$discsFiles,$PRINT,$metagroups) = @_; my %done; local *A; my $a; if ($PRINT) { open A, ">$PRINT"; $a = \*A } else { $a = $config->{LOG}} my $print_rejected = sub { my ($groups,$i,$rpm) = @_; $done{$groups->[$i]{urpm}{rpmkey}{rpm}{$rpm}} and return 1; if ($groups->[$i]{brokendeps}{$rpm} == 2){ ref $groups->[$i]{rejected}{$rpm} or print { $a } "ERROR printDiscsFile: this should not happen, rejected is not a table for $rpm (group $i)\n" and next; } print { $a } "REJECTED $rpm ("; ref $groups->[$i]{rejected}{$rpm} and print { $a } (join ',', map { "$config->{rejected_options}{$_->[0]}: $_->[1]" } @{$groups->[$i]{rejected}{$rpm}}); print { $a } ")\n"; 0 }; for (my $cd; $cd < @$discsFiles; $cd++){ $discsFiles->[$cd] or next; print { $config->{LOG} } "discsFiles: $cd\n"; my $cdname = $config->{disc}[$cd]{label}; foreach my $rep (keys %{$discsFiles->[$cd]}){ foreach my $list (keys %{$discsFiles->[$cd]{$rep}}){ foreach my $rpm (sort keys %{$discsFiles->[$cd]{$rep}{$list}}){ $done{$rpm} = 1; #$rpm =~ /src$/ and next; print { $a } "$cdname $rpm\n"; } } } } if (!$metagroups) { $a = $config->{LOG} } foreach (@$metagroups){ my $groups = $_->[0]; for (my $i; $i < @$groups; $i++){ if (ref $groups->[$i]{buildlist}){ foreach (sort @{$groups->[$i]{buildlist}}){ $print_rejected->($groups,$i,$_) and next; $done{$groups->[$i]{urpm}{rpmkey}{rpm}{$_}} = 1 } } foreach (sort keys %{$groups->[$i]{urpm}{rpm}}){ $print_rejected->($groups,$i,$_) and next; } } } close A; } sub printBatchFile{ my ($config,$discsFiles,$PRINTSCRIPT) = @_; if (-f $PRINTSCRIPT) { my $err = unlink $PRINTSCRIPT; if (!$err) { print { $config->{LOG} } "Unlinking failed $PRINTSCRIPT: $!\n"; return}; } my $err = copy $config->{configfile}, $PRINTSCRIPT; if (!$err) { print { $config->{LOG} } "Linking failed $PRINTSCRIPT: $!\n"; return}; local *A; open A, ">>$PRINTSCRIPT"; print A "END\n"; for (my $cd; $cd < @$discsFiles; $cd++){ $discsFiles->[$cd] or next; print { $config->{LOG} } "discsFiles: $cd\n"; print A "CD $cd\n"; foreach my $rep (keys %{$discsFiles->[$cd]}){ print A " REP $rep\n"; foreach my $list (keys %{$discsFiles->[$cd]{$rep}}){ print A " LIST $list\n"; foreach my $rpm (keys %{$discsFiles->[$cd]{$rep}{$list}}){ $rpm and print A " $rpm $discsFiles->[$cd]{$rep}{$list}{$rpm}\n"; } } } } } sub readBatchFile{ my ($file) = @_; local *A; open A, "$file" or print "ERROR readBatchFile: could not open $file for reading\n" and return 0; my @discsFiles; my @cd; while (){ /^END/ and last } my ($cd,$rep,$list); while (){ if (/^CD (\d+)/){ $cd = $1; next } if (/^ REP (\S+)/){ $rep = $1; next } if (/^ LIST (\d+)/){ $list = $1; next } if (/^ (\S+) (\S+)/){ $discsFiles[$cd]{$rep}{$list}{$1} = $2; push @{$cd[$cd]{$rep}{$list}{$2}}, [ 1, "$1.rpm" ]; next } } return (\@discsFiles, \@cd) } sub config{ my ($file,$config,$functions) = @_; open F,$file or die "ERROR config: cannot open $file\n"; while (){ chomp ; /^#/ or !$_ or last } chomp; $config->{name} = (split)[0]; my $match_val = q((?:([^"\s]+)|"([^\"]+)")); my $match_val2 = q(([^"\s]+|"[^\"]+")); my ($cd,$fn,$nk,$type,@todo,$discMax); while (){ /^#/ and next; chomp; $_ or next; s/#.*//; if (/^LIST /){ if (/^LIST (\d+)(?:\s+(\S.*))*/) { $cd = $1; push @{$config->{list}[$cd]{filelist}}, (split ' ',$2); $type = 1; print LOG "LIST $1 $2\n" }else { $nk = 1; print LOG "WARNING: LIST syntax error ($_)\n"; print LOG " LIST ... \n" } } elsif (/^disc (.*)/) { my $line = $1; my @args; while ($line =~ s/$match_val2//){my $a = $1; $a =~ s/\"//g; push @args, $a } print "config: args (" . ( join ' | ', @args) . ")\n"; my $todo = parseCommandLine("disc",\@args,$functions->{disc}); $cd = $todo->[0][1][0]; print "config: disc $cd (@{$todo->[0][1]})\n"; if (!$config->{disc}[$cd]){ @args and usage('disc',$functions->{disc},"disc $cd, disc definition (@args) too many arguments"); foreach (@$todo){ print LOG "$_->[2]\n"; &{$_->[0]}($cd,@{$_->[1]}) or print LOG "ERROR: $_->[2]\n" and $nk = 1; } $type = 2; $fn = 0 } else { $type = 0; print LOG "ERROR config: disc $cd already defined, ignoring\n"; } # FIXME keep for compatibility } elsif (/^DISC (.*)/) { if (/^DISC (\d+)\s+(\d+)\s+$match_val(?:\s+DISC\s+(\d+))?\s+$match_val(?:\s+$match_val)?/) { #print "1($1) 2($2) 3($3) 4($4) 5($5) 6($6) 7($7) 8($8) 8($9)\n"; $config->{disc}[$1]{size} = $2; my $disc = $config->{disc}[$1]; $disc->{serial} = substr "$3$4", 0, 128; $disc->{name} = $5; $disc->{longname} = "$6$7"; $disc->{appname} = substr ("$6$7", 0, 128); $disc->{label} = substr (("$6$7" ? "$8$9" : "$6$7"), 0, 32); $cd = $1; $type = 2; $fn = 0; $4 > $discMax and $discMax = $4; print LOG "DISC $1 $2 $3$4 $5 $6$7 $8$9\n" }else{ $nk = 1; $type = 0; print LOG "WARNING: DISC syntax error ($_)\n"; print LOG " DISC DISC \n"; } } elsif (/^END/){ last }else { $type == 1 and do { push @{$config->{list}[$cd]{packages}}, [split]; next }; $type == 2 and do { my ($prog,@args) = split; print LOG "CALLING $prog -- @args\n"; push @todo, [$prog, \@args, $cd, $fn]; $fn++; next } } } $config->{configfile} = $file; $config->{discMax} = $discMax; foreach (@todo){ my ($prog,$args,$cd,$fn) = @$_; $functions->{$prog} and do { print LOG "FUNCTION $prog\n"; my $todo = parseCommandLine($prog,$args,$functions->{$prog}); @$args and usage($prog,$functions->{$prog},"disc $cd, function $fn, @$args, too many arguments"); foreach (@$todo){ print LOG "$_->[2]\n"; &{$_->[0]}($cd,$fn,@{$_->[1]}) or print LOG "ERROR: $_->[2]\n" and $nk = 1; } } } $nk and return 0; #printTable($config); 1 } sub compute_md5{ my ($to_check,$ignore) = @_; my @files; md5_add_tree($to_check,\@files,$ignore); my $md5 = new Digest::MD5; foreach (sort { $a->[0] cmp $b->[0] } @files){ my $f = $_->[1]; local *A, open A, "$f"; $md5->addfile(*A); #my $tmpmd5 = new Digest::MD5; #local *A, open A, "$f"; #$tmpmd5->addfile(*A); #print "MD5: $_->[0] (", $tmpmd5->hexdigest() ,")\n"; } my $digest = $md5->hexdigest(); # print "IGNORE " , join " ",keys %$ignore ,"\n"; return $digest } sub md5_add_tree{ my ($to_check,$files,$ignore) = @_; foreach (@$to_check){ my ($dest,$f) = @$_; $f =~ /\/?\.{1,2}$/ and next; $f =~ /~$/ and next; $f =~ s/\/\/+/\//g; $dest =~ s/\/\/+/\//g; $ignore->{$dest} and next; if (-d $f){ local *A; opendir A, $f; md5_add_tree([ map { [ "$dest/$_", "$f/$_" ] } readdir A ], $files, $ignore) }else{ push @$files, [ $dest, $f ] } } } sub log_ { my ($msg,$verbose,$log) = @_; #print "message $msg verbose $verbose\n"; my $LOG; if (!$log){ open $LOG, ">&STDERR" } else { $LOG = $log } $verbose and print { $LOG } $msg; } # TODO must add some check of maximum authorized size sub include_md5 { my ($iso,$write,$verbose) = @_; local *ISO; if ($write){ open ISO, "+<$iso" or return "ERROR include_md5: unable to open $iso ($!)\n"; } else { open ISO, $iso or return "ERROR include_md5: unable to open $iso ($!)\n"; } binmode ISO; my $offset = 16*2048; seek ISO, $offset, 0; my ($buf,$msg); while (1){ read ISO,$buf,2048; my $c = ord $buf; last if $c == 1; return "ERROR include_md5: could not find primary volume descriptor\n" if $c == 255; $offset += 2048 } my $size = ((ord substr $buf, $SIZE_OFFSET, 1) * 0x1000000 + (ord substr $buf, $SIZE_OFFSET + 1, 1) * 0x10000 + (ord substr $buf, $SIZE_OFFSET + 2, 1) * 0x100 + (ord substr $buf, $SIZE_OFFSET + 3, 1) ) * 2048; my $volume = substr $buf, 30, 40; $volume =~ s/^\s*(\S.*\S)\s*$/$1/; $msg = "include_md5: volume name $volume iso size $size\n"; seek ISO, $offset + $INFO_OFFSET, 0; read ISO, $buf,512; my ($md5sum) = $buf =~ /.md5 = (\S+)/; $msg .= "include_md5: previous data $buf\n"; seek ISO, 0, 0; my $md5 = new Digest::MD5; my $read = read ISO, $buf, $offset + $INFO_OFFSET; $md5->add($buf); seek ISO, 512, 1; $read += 512; while ($read < ($size - ($SKIP * 2048))){ my $n = read ISO, $buf,2048; $md5->add($buf); $read += $n; } my $digest = $md5->hexdigest(); $msg .= "include_md5: computed md5 $digest\n"; my $res = $md5sum eq $digest; if ($md5sum){ $msg .= "include_md5: previous md5 $md5sum\ninclude_md5: md5sum check "; $msg .= $res ? "OK\n" : "FAILED\n" } print $msg if $verbose; $write or return $res; seek ISO, $offset + $INFO_OFFSET, 0; my $str = substr "$volume.md5 = $digest", 0, 512; my $l = length $str; print ISO ($l > 512 ? substr $str, -1, 512 : $str . ' ' x (512 - $l)); } 1 # # Changelog # # 2002 02 27 # make the locale constraint free on the right for cleanrpmsrate locale addition (kde-i18n-zh_BG and such) # # 2002 03 03 # fix typo in checkdiscs # # 2002 03 04 # fix checkcds pb with check[0] used. # # 2002 03 07 # add possibility to remove package from rpmsrate # # 2002 03 12 # add all .*kernel- in rpmsrate # # 2002 03 17 # add serial name instead of cdnumber when name is not know # # 2002 05 07 # add check_discs, compute_md5, write_graft, md5_add_tree # # 2002 05 22 # fix a pb in md5 # # 2002 05 25 # add log function # # 2002 06 05 # fix md5 for isolinux # # 2002 08 12 # fix/change cleanrpmsrate # # 2002 09 04 # do not open for writing iso file in include_md5 if not in write mode