# -*- perl -*-
-# $Id: errorlib.in,v 1.3 1999/12/01 18:04:01 gecko Exp $
+# $Id: errorlib.in,v 1.29 2003/06/06 17:56:05 cjwatson Exp $
sub F_SETLK { 6; } sub F_WRLCK{ 1; }
$flockstruct= 'sslll'; # And there ought to be something for this too.
+sub get_hashname {
+ return "" if ( $_[ 0 ] < 0 );
+ return sprintf "%02d", $_[ 0 ] % 100;
+}
+
sub unlockreadbugmerge {
local ($rv) = @_;
&unfilelock if $rv >= 2;
}
sub lockreadbugmerge {
- local ($lref) = @_;
- if (!&lockreadbug($lref)) { return 0; }
- if (!length($s_mergedwith)) { return 1; }
+ local ($lref, $location) = @_;
+ local $data;
+ if (!($data = &lockreadbug($lref, $location))) { return ( 0, undef ); }
+ if (!length($data{mergedwith})) { return ( 1, $data ); }
&unfilelock;
&filelock('lock/merge');
- if (!&lockreadbug($lref)) { &unfilelock; return 0; }
- return 2;
+ if (!&lockreadbug($lref, $location)) { &unfilelock; return ( 0, undef ); }
+ return ( 2, $data );
+}
+
+sub getbuglocation {
+ my ( $bugnum, $ext ) = @_;
+ my $archdir = sprintf "%02d", $bugnum % 100;
+ return 'archive' if ( -r "$gSpoolDir/archive/$archdir/$bugnum.$ext" );
+ return 'db-h' if ( -r "$gSpoolDir/db-h/$archdir/$bugnum.$ext" );
+ return 'db' if ( -r "$gSpoolDir/db/$bugnum.$ext" );
+ return undef;
+}
+
+sub getlocationpath {
+ my ($location) = @_;
+ if ($location eq 'archive') {
+ return "$gSpoolDir/archive";
+ } elsif ($location eq 'db') {
+ return "$gSpoolDir/db";
+ } else {
+ return "$gSpoolDir/db-h";
+ }
+}
+
+sub getbugcomponent {
+ my ($bugnum, $ext, $location) = @_;
+
+ $location = getbuglocation($bugnum, $ext) unless defined $location;
+ my $dir = getlocationpath($location);
+ return undef unless $dir;
+ if ($location eq 'db') {
+ return "$dir/$bugnum.$ext";
+ } else {
+ my $hash = get_hashname($bugnum);
+ return "$dir/$hash/$bugnum.$ext";
+ }
+}
+
+sub readbug {
+ local ($lref, $location) = @_;
+ my $status = getbugcomponent($lref, 'status', $location);
+ return undef unless defined $status;
+ if (!open(S,$status)) { return undef; }
+ my %data;
+ chop($data{originator}= <S>);
+ chop($data{date}= <S>);
+ chop($data{subject}= <S>);
+ chop($data{msgid}= <S>);
+ chop($data{package}= <S>);
+ chop($data{keywords}= <S>);
+ chop($data{done}= <S>);
+ chop($data{forwarded}= <S>);
+ chop($data{mergedwith}= <S>);
+ chop($data{severity}= <S>);
+ chop($data{versions}= <S>);
+ chop($data{fixed_versions}= <S>);
+ close(S);
+ $data{severity} = 'normal' if $data{severity} eq '';
+ return \%data;
}
sub lockreadbug {
- local ($lref) = @_;
+ local ($lref, $location) = @_;
&filelock("lock/$lref");
- if (!open(S,"db/$lref.status")) { &unfilelock; return 0; }
- chop($s_originator= <S>);
- chop($s_date= <S>);
- chop($s_subject= <S>);
- chop($s_msgid= <S>);
- chop($s_package= <S>);
- chop($s_keywords= <S>);
- chop($s_done= <S>);
- chop($s_forwarded= <S>);
- chop($s_mergedwith= <S>);
- chop($s_severity= <S>);
- close(S);
- $s_severity = 'normal' if $s_severity eq '';
- return 1;
+ my $data = readbug($lref, $location);
+ &unfilelock unless defined $data;
+ return $data;
+}
+
+sub writebug {
+ local ($ref, $data, $location) = @_;
+ my $change;
+ my $status = getbugcomponent($ref, 'status', $location);
+ &quit("can't find location for $ref") unless defined $status;
+ open(S,"> $status.new") || &quit("opening $status.new: $!");
+ print(S
+ "$data->{originator}\n".
+ "$data->{date}\n".
+ "$data->{subject}\n".
+ "$data->{msgid}\n".
+ "$data->{package}\n".
+ "$data->{keywords}\n".
+ "$data->{done}\n".
+ "$data->{forwarded}\n".
+ "$data->{mergedwith}\n".
+ "$data->{severity}\n".
+ "$data->{versions}\n".
+ "$data->{fixed_versions}\n") || &quit("writing $status.new: $!");
+ close(S) || &quit("closing $status.new: $!");
+ if (-e $status) {
+ $change = 'change';
+ } else {
+ $change = 'new';
+ }
+ rename("$status.new",$status) ||
+ &quit("installing new $status: $!");
+ &bughook($change,$ref,
+ "$data->{originator}\n".
+ "$data->{date}\n".
+ "$data->{subject}\n".
+ "$data->{msgid}\n".
+ "$data->{package}\n".
+ "$data->{keywords}\n".
+ "$data->{done}\n".
+ "$data->{forwarded}\n".
+ "$data->{mergedwith}\n".
+ "$data->{severity}\n".
+ "$data->{versions}\n".
+ "$data->{fixed_versions}\n");
+}
+
+sub unlockwritebug {
+ writebug(@_);
+ &unfilelock;
}
sub filelock {
}
sub unfilelock {
+ if (@filelocks == 0) {
+ warn "unfilelock called with no active filelocks!\n";
+ return;
+ }
local ($lockfile) = pop(@filelocks);
pop(@cleanups);
- eval 'close(FLOCK'.($#filelocks+1).');' || warn "failed to close lock file: $!";
- unlink($lockfile) || warn "failed to remove lock file: $!";
+ eval 'close(FLOCK'.($#filelocks+1).');' || warn "failed to close lock file $lockfile: $!";
+ unlink($lockfile) || warn "failed to remove lock file $lockfile: $!";
}
sub quit {
$out;
}
-@severities= @gSeverityList;
+sub update_realtime {
+ my ($file, $bug, $new) = @_;
+
+ # update realtime index.db
+
+ open(IDXDB, "<$file") or die "Couldn't open $file";
+ open(IDXNEW, ">$file.new");
+
+ my $line;
+ my @line;
+ while($line = <IDXDB>) {
+ @line = split /\s/, $line;
+ last if ($line[1] >= $bug);
+ print IDXNEW $line;
+ $line = "";
+ }
+
+ if ($new eq "NOCHANGE") {
+ print IDXNEW $line if ($line ne "" && $line[1] == $ref);
+ } elsif ($new eq "REMOVE") {
+ 0;
+ } else {
+ print IDXNEW $new;
+ }
+ if ($line ne "" && $line[1] > $bug) {
+ print IDXNEW $line;
+ $line = "";
+ }
+
+ print IDXNEW while(<IDXDB>);
+
+ close(IDXNEW);
+ close(IDXDB);
+
+ rename("$file.new", $file);
+
+ return $line;
+}
+
+sub bughook_archive {
+ my $ref = shift;
+ &filelock("debbugs.trace.lock");
+ &appendfile("debbugs.trace","archive $ref\n");
+ my $line = update_realtime(
+ "$gSpoolDir/index.db.realtime",
+ $ref,
+ "REMOVE");
+ update_realtime("$gSpoolDir/index.archive.realtime",
+ $ref, $line);
+ &unfilelock;
+}
+
+sub bughook {
+ my ( $type, $ref ) = ( shift, shift );
+ &filelock("debbugs.trace.lock");
+
+ &appendfile("debbugs.trace","$type $ref\n",@_);
+
+ my @stuff=split /\n/, "$_[0]\n\n\n\n\n\n\n";
+
+ my $whendone = "open";
+ my $severity = $gDefaultSeverity;
+ (my $pkglist = $stuff[4]) =~ s/[,\s]+/,/g;
+ $pkglist =~ s/^,+//;
+ $pkglist =~ s/,+$//;
+ $whendone = "forwarded" if length $stuff[7];
+ $whendone = "done" if length $stuff[6];
+ $severity = $stuff[9] if length $stuff[9];
+
+ my $k = sprintf "%s %d %d %s [%s] %s %s\n",
+ $pkglist, $ref, $stuff[1], $whendone, $stuff[0],
+ $severity, $stuff[5];
+
+ update_realtime("$gSpoolDir/index.db.realtime", $ref, $k);
+
+ &unfilelock;
+}
+
+sub appendfile {
+ my $file = shift;
+ if (!open(AP,">>$file")) {
+ print DEBUG "failed open log<\n";
+ print DEBUG "failed open log err $!<\n";
+ &quit("opening $file (appendfile): $!");
+ }
+ print(AP @_) || &quit("writing $file (appendfile): $!");
+ close(AP) || &quit("closing $file (appendfile): $!");
+}
+
+sub getmailbody {
+ my $entity = shift;
+ my $type = $entity->effective_type;
+ if ($type eq 'text/plain' or
+ ($type =~ m#text/# and $type ne 'text/html') or
+ $type eq 'application/pgp') {
+ return $entity->bodyhandle;
+ } elsif ($type eq 'multipart/alternative') {
+ # RFC 2046 says we should use the last part we recognize.
+ for my $part (reverse $entity->parts) {
+ my $ret = getmailbody($part);
+ return $ret if $ret;
+ }
+ } else {
+ # For other multipart types, we just pretend they're
+ # multipart/mixed and run through in order.
+ for my $part ($entity->parts) {
+ my $ret = getmailbody($part);
+ return $ret if $ret;
+ }
+ }
+ return undef;
+}
+
+sub escapelog {
+ my @log = @_;
+ map { s/^([\01-\07\030])/\030$1/gm } @log;
+ return \@log;
+}
+
+
+@severities= grep { not exists $gObsoleteSeverities{$_} } @gSeverityList;
@showseverities= @severities;
grep ($_= $_ eq '' ? $gDefaultSeverity : $_, @showseverities);
@strongseverities= @gStrongSeverities;