#!/usr/bin/perl # I created this script to help me reinstall all # broken packages required to emerge qemu. # I used it like this: # ./fix_broken_packages.pl app-emulation/qemu-0.11.1 # The script will create fix_broken_packages.cache # file in the current directory, to speed up # the next run in case something goes wrong. use strict; use warnings; use Storable; my $cache_fn = 'fix_broken_packages.cache'; my $cache = eval { retrieve $cache_fn } || [ {}, {} ]; my %dep_cache = %{$cache->[0]}; my %pkg_ok = %{$cache->[1]}; sub deps { my $pkg = shift; return @{$dep_cache{$pkg}} if defined $dep_cache{$pkg}; print "Checking deps of $pkg\n"; open my $dep_graph_fh, '-|', 'equery', 'g', $pkg or die("Error running equery g with package $pkg\n"); my @deps; while(<$dep_graph_fh>) { chomp; next if /^$/; if (/^(.*):$/) { die ("Package name don't match: $1 <> $pkg\n") if $1 ne $pkg; next; } /^ \[([0-9 ]+)\] (.*?) *$/ or die("Unexpected equery g output: $_\n"); next if $1 == 0; push @deps, $2; } close $dep_graph_fh; $dep_cache{$pkg} = [ @deps ]; return @deps; } sub is_installed { my $pkg = shift; $pkg =~ s!^(.*?)/(.*?)-.*$!$1/$2!; for(`qlist -C -I`) { chomp; return 1 if $_ eq $pkg; } return 0; } sub is_broken { my $pkg = shift; return 0 if $pkg_ok{$pkg}; return 0 if !is_installed($pkg); print "Checking files of $pkg\n"; open my $verify_fh, "equery -N k '$pkg' 2>&1 |" or die("Error running equery k with package $pkg\n"); while(<$verify_fh>) { chomp; last if /^!!! No installed packages matching /; next if /^!!! .* has incorrect MD5sum$/; next if /^!!! .* has wrong mtime /; next if /^\* Checking /; next if /^ \d+ out of \d+ files passed$/; if (/^!!! (.*) does not exist$/) { my $fname = $1; next if $fname =~ m!^/usr/share/(doc|man|info)/!; print "$_\n"; return 1; } if (/^Traceback \(most recent call last\):$/) { print "Warning - equery crashed!\n"; return 1; } die("Unexpected equery k output: $_"); } close $verify_fh; $pkg_ok{$pkg} = 1; return 0; } my %seen; my $cache_save_time = time(); sub fix_deps { store [ { %dep_cache }, { %pkg_ok } ], $cache_fn if time() - $cache_save_time > 5; my $pkg = shift; for(deps($pkg)) { my $pkg = $_; next if !is_installed($pkg); if (!defined $seen{$pkg}) { $seen{$pkg} = 1; fix_deps($pkg); } if (is_broken($pkg)) { system('emerge', ">=$pkg") == 0 or die("emerge >=$pkg failed \n"); } } } my $pkg = $ARGV[0] || die("Usage: $0 package_name"); fix_deps($pkg);