#!/usr/bin/perl # Copyright 2007 (C) Kees Cook # License: GPLv2 # # This script attempts to find and download a specific version of a Debian # package and its immediate parent to generate a debdiff. # # Requirements: devscripts diffstat dpkg-dev # # Cleanups needed: # - general cleanup # - parse diff.gz/orig.tar.gz from .dsc file instead of guessing version use strict; use warnings; sub geturls { my ($urlbase,$pkg,$version)=@_; my $file; $file = "${pkg}_${version}.dsc"; warn "Trying $urlbase/$file ...\n"; if (! -r "$file") { system("wget $urlbase/$file"); return 0 if ($? != 0); } warn "Pulling source of $urlbase/$file ...\n"; $file = "${pkg}_${version}.diff.gz"; if (! -r "$file") { system("wget $urlbase/$file"); return 0 if ($? != 0); } my $orig_ver = $version; $orig_ver =~ s/-.*//; $file = "${pkg}_${orig_ver}.orig.tar.gz"; if (! -r "$file") { system("wget $urlbase/$file"); return 0 if ($? != 0); } return 1; } sub generate_base { my ($pkg)=@_; my @path; push(@path,"main"); if ($pkg =~ /^(lib.)/) { push(@path,$1); } else { push(@path,substr($pkg,0,1)); } push(@path,$pkg); return join("/",@path); } sub download_source { my ($pkg,$version)=@_; my $urlbase; my $base = generate_base($pkg); # Attempt to pull from security updates first $urlbase = "http://security.debian.org/pool/updates/$base"; if (!geturls($urlbase,$pkg,$version)) { # Try regular pool $urlbase = "http://ftp.debian.org/debian/pool/$base"; if (!geturls($urlbase,$pkg,$version)) { # Try snapshot $urlbase=`curl -sI 'http://snapshot.debian.net/package/$pkg/$version' | grep ^[lL]ocation | cut -d' ' -f2 | head -1`; $urlbase =~ s/[\r\n]//g; warn "Trying snapshot location '$urlbase' ...\n"; if ($urlbase ne "" && !geturls($urlbase,$pkg,$version)) { return 0; } } } return 1; } my $pkg = $ARGV[0]; my $version = $ARGV[1]; my $skip = $ARGV[2] || 1; $skip+=0; if (!defined($pkg) || !defined($version)) { die "Usage: $0 PKG VERSION\n"; } # Extract latest source die "Cannot locate $pkg $version\n" unless download_source($pkg,$version); system("dpkg-source -x ${pkg}_${version}.dsc"); die "Unpack of $pkg $version failed\n" unless ($? == 0); # Locate prior changelog entry my $prev_ver; my $srcdir; opendir(DIR,"."); while ($srcdir = readdir(DIR)) { last if ($srcdir =~ /^${pkg}-/ && -d $srcdir); } closedir(DIR); die "Cannot locate source tree\n" if (!defined($srcdir)); open(LOG,"<$srcdir/debian/changelog"); while (my $line=) { if ($line =~ /^$pkg \((?:\d+:)?([^\)]+)\)/) { my $seen = $1; if ($seen ne $version) { $skip--; if ($skip==0) { $prev_ver=$seen; last; } } } } close(LOG); die "Cannot find earlier source version\n" if (!defined($prev_ver)); die "Cannot locate $pkg $prev_ver\n" unless download_source($pkg,$prev_ver); system("dpkg-source -x ${pkg}_${prev_ver}.dsc"); die "Unpack of $pkg $prev_ver failed\n" unless ($? == 0); system("debdiff ${pkg}_${prev_ver}.dsc ${pkg}_${version}.dsc > ${pkg}_${version}.debdiff"); die "Cannot debdiff\n" unless ($? == 0); system("diffstat -p0 ${pkg}_${version}.debdiff"); print "${pkg}_${version}.debdiff\n";