dbupdate.pl fix
Marten Terpstra
Wed Dec 14 11:50:17 CET 1994
Folks, dbupdate has a small bug where it can fail to do the proper indexing when handling multiple indexes (ie a mix or routes, inetnums and inet-rtrs). It can fail to use the correct index when one of the objects generates warnings and/or errors. Please replace src/dbupdate.pl with the one below and run a "make install" in the top level database directory. -Marten PS For all who are running "older" versions of the DB or have not kept up with all patches I have been sending out, the version on ftp://ncc.ripe.net/dbase-beta/dbase-beta.tar.gz is kept up-to-date. #!PERL # $RCSfile: dbupdate.pl,v $ # $Revision: 0.31 $ # $Author: marten $ # $Date: 1994/12/14 10:40:55 $ # This is a client that will update objects read from a file directly # in the database, without interference of updated. # It will update the object in the database that is linked to the # source field of the object, so better make sure you have a source field # and that it has a database associated to it ... @INC = ("LIBDIR", @INC); require "adderror.pl"; require "cldb.pl"; require "dbadd.pl"; require "dbclose.pl"; require "dbopen.pl"; require "defines.pl"; require "enparse.pl"; require "entype.pl"; require "enwrite.pl"; require "getopts.pl"; require "handle.pl"; require "misc.pl"; require "rconf.pl"; require "rfc822.pl"; require "syslog.pl"; # Parse options: # # -l logfile - log output to file in stead of STDOUT # -v - verbose output (LONGACK) # -M - treat input file (or STDIN) as mail and compose # and send ack mail back # -A - assume "assign" mode, only add will be allowed # usually set by parsing mail headers # -H - handle assignment mode. Will only accept persons # with nic-handle "assign" and return person entry # with the handle assigned and filled in. # (very RIPE database dependent) &Getopts('l:vMAHV'); # Need this below for running perl in tainted mode. $ENV{"PATH"} = ""; $ENV{"SHELL"} = "/bin/sh"; $ENV{"IFS"} = ""; # Read config file from RIPEDBCNF, or set to default. $conffile=$ENV{"RIPEDBCNF"}; $conffile= "DEFCONFIG" unless $conffile; print STDERR "dbupdate - reading config\n" if $opt_V; &rconf($conffile); # Save STDOUT open(SAVEOUT, ">&STDOUT"); # Open one ack file. Proper handling (stdout, logfile or mail) is handled # all the way at the end .... But, we open the logfile if needed already # because we need to exit if we cannot even create that file ... # If -M option is specified, -l is overruled. if ($opt_l) { open(LOGFILE, ">$opt_l") || die "Cannot create $opt_l: $!"; } open(STDOUT, ">$TMPDIR/dbupdack.$$") || &syslog("ERRLOG", "cannot create tmp ack file: $!"); # Make STDOUT unbuffered select(STDOUT); $| = 1; # # printstat ( arg ) # # int arg /* 0=failed, 1=ok, 2=noop */ # # prints verbose version of the update result. # sub printstat { local($stat) = @_; local($type) = &entype(*entry); print STDERR "dbupdate - printstat($stat) called\n" if $opt_V; print STDERR "dbupdate - printstat 1\n" if $opt_V; if ($hasdelete) { print "Delete "; } else { print "Update "; } print STDERR "dbupdate - printstat 2\n" if $opt_V; if ($stat == 1) { print "OK: ";} elsif ($stat == 2) { print "NOOP: ";} else { print "FAILED: "; } print STDERR "dbupdate - printstat 3\n" if $opt_V; print "[$ATTL{$type}] $entry{$type}\n\n"; print STDERR "dbupdate - printstat 4\n" if $opt_V; } # # doaction ( ) # # does all the work. # sub doaction { local($file) = @_; local($donestat) = 0; print STDERR "dbupdate - doaction($file) called\n" if $opt_V; while(1) { $donestat = 0; print STDERR "dbupdate - calling enparse\n" if $opt_V; ($parsestat, %entry) = &enparse($file); # next if nothing was read next if $parsestat == $NOK; # return if only thing read was EOF return if $parsestat == $EOF; $somethingfound = 1; print STDERR "dbupdate - read an object\n" if $opt_V; # Now, let's check whether this is a delete request or not # If it is, we have to skip all syntax checks ... # A wrongly defined delete attribute will return a 0, # and add a error message. $hasdelete = &hasdelete(*entry); # object parsing generated an error, output object with # errors and return. If we are deleting an object, then # forget about it, we do not want to return with syntax # errors local($type) = &entype(*entry); # now if we are running in -H mode, just next when we have # not found a person. if ($opt_H) { if ($type ne "pn") { print "No person object found\n"; next; } else { if ($entry{"nh"} !~ /^[aA][sS][sS][iI][gG][nN]$/) { &adderror(*entry, "nichandle \"assign\" expected"); print "\n" if &enwrite(*entry,1,1); next; } } } if (($parsestat == $O_ERROR) && (!$hasdelete)) { print STDERR "dbupdate - object has error and no delete\n" if $opt_V; if ($opt_v) { &printstat(0); } $haserror = 1; print "\n" if &enwrite(*entry,1,1,1); next; } # If we have to delete, remove all parse errors and warnings # and set status to OK: we do not want deletes to be checked if ($hasdelete) { &rmwarnings(*entry); &rmerrors(*entry); $parsestat= $O_OK; } # object parsed OK or has only warnings if ($parsestat == $O_OK || $parsestat == $O_WARNING) { # open database file associated with "so" for writing local(*db) = 'currentdb'; print STDERR "dbupdate - opening database\n" if $opt_V; if (&dbopen(db, *entry, 1)) { # Open classless database print STDERR "dbupdate - opening classless db\n" if $opt_V; &dbclopen(*entry,1); # Looks like we have some locking problem, so let's # lock the thing before we do anything else ... print STDERR "dbupdate - locking databases\n" if $opt_V; &dblock(*db); # do we delete or not ? if ($hasdelete) { print STDERR "dbupdate - deleting entry\n" if $opt_V; $dbstat = &dbdel(*db, *entry); # We do handle generation, so after a delete, we # have to delete the handle from that database # as well. if ($DOHANDLE && $HANDLEATTR{$type}) { if ($dbstat == $OK) { &DeleteHandle(*entry); } } } else { # We do handle generation, check whether we have # to assign a nic handle (if nh value is "assign") # Can be a request handle of form: assign handle # Line has already been syntax checked, so no worries # there. Errors are added by AssignHandle, so all we # need is an extra check. if ($DOHANDLE && $HANDLEATTR{$type}) { if ($entry{$HANDLEATTR{$type}} =~ /^[Aa][Ss][Ss][Ii][Gg][Nn]\s*(.*)$/) { local($handle) = &AssignHandle(*entry, $1); } else { # new object, we may have to put the handle # in the database. AddHandle will return if # if the handle is already in handle database &AddHandle(*entry); } } if (!&haserror(*entry)) { # NEW assignments && !person if ($opt_A && ($type ne "pn")) { print STDERR "dbupdate - calling dbadd\n" if $opt_V; $dbstat = &dbadd(*db, *entry); } else { print STDERR "dbupdate - calling add_or_mod\n" if $opt_V; $dbstat = &dbadd_or_modify(*db, *entry); } } else { # Fake dbstat, has error due to handle # generation ... $dbstat = $OK; } } # Totally yucky, but I do not know how to # do this better right now. The thing is that # every exit code but E_NOOP and OK are # errors, so catch NOOP first, and print # verbose warning if needed, then OK, and # then handle all the others as errors. # noop, just print stat if verbose print STDERR "dbupdate - doing acks\n" if $opt_V; if ($dbstat == $E_NOOP && $opt_v) { &printstat(2); $donestat = 1; } elsif (($dbstat != $OK) && ($dbstat != $E_NOOP)){ &adderror(*entry, "$MESSAGE[$dbstat]"); } # Object has errors, so print, and next if (&haserror(*entry)) { print STDERR "dbupdate - object has errors\n" if $opt_V; $haserror = 1; if ($opt_v) { &printstat(0); } print "\n" if &enwrite(*entry,1,1); &dbunlock(*db); &dbclose(*db); &dbclclose(); next; } # object has only warnings, so it must have # been processed. print and next. elsif (&haswarning(*entry)) { print STDERR "dbupdate - object has warnings\n" if $opt_V; $haserror = 1; if (!$donestat && $opt_v) { &printstat(1); } print "\n" if &enwrite(*entry,1,1); &dbunlock(*db); &dbclose(*db); &dbclclose(); next; } # all was OK, so only print stat if verbose if ($opt_v && !$donestat) { &printstat(1); } # all was OK, print object if nichandle assign mode if ($opt_H) { &enwrite(*entry,1,1); } &dbunlock(*db); &dbclose(*db); &dbclclose(); } else { # Not too good, probably permission problem # if this is given as output ... &adderror(*entry, "Failed to open DB file: $!"); &adderror(*entry, "Please check the \"source:\" value"); &adderror(*entry, "Contact <$HUMAILBOX> if source seems ok"); &printstat(0); &enwrite(*entry,1,1); } } } close(TMP); } # # Main program # # We want to make a local copy of the input, because we need to do mutliple # things with it ... open(COPY, ">$TMPDIR/dbupdcopy.$$") || die "Cannot open copy file: $!"; select(COPY); $| = 1; select(STDOUT); while (<>) { print COPY; } close(COPY); # Now we open the copy to actually process open(COPY, "$TMPDIR/dbupdcopy.$$") || die "Cannot open copy: $!"; # We have a mail, so let's first parse the headers ... if ($opt_M) { local($stat) = &parserfc822(COPY); # If we have at least a return address, compose the header of # the ack mail if ($stat) { if ($TESTMODE) { print "To: $DEFMAIL\n"; } else { print "To: $FROM\n"; } eval "print \"$MHEADER\";"; eval "print \"$MAILTXT\";"; # If not we are in trouble once more ... } else { print "Header could not be parsed ...\n"; } } # Take all the stuff from file COPY in doaction. It will process the # whole stuff. &doaction(COPY); if (!$somethingfound) { print "** No objects were found in your message **\n"; } elsif ($haserror) { print "$ACKERR" unless $opt_H; } else { print "$ACKOK" unless $opt_H; } print $ACKSIG unless $opt_H; close(COPY); close(STDOUT); open(STDOUT, ">&SAVEOUT"); # Output the ack, if -M specified then no logfile or stdout will be given. if ($opt_M) { system("$MAILCMD < $TMPDIR/dbupdack.$$"); } else { open(TMP, "$TMPDIR/dbupdack.$$"); while (<TMP>) { if ($opt_l) { print LOGFILE; } else { print; } } close(TMP); } # We sent out the ack, now send out the notifications if needed if (%notify) { &SendNotifications(); } if (%forward) { &SendForwardMails(); } # log all stuff to the right places # todays YYMMDD local($s,$m,$h,$md,$mo,$y,$wd,$yd,$is) = localtime(time); $mo+=1; $mo = "0".$mo unless $mo > 9; $md = "0".$md unless $md > 9; $y = "0".$y unless $y > 9; $YYMMDD = "$y$mo$md"; # This may seem yucky, but is needed to untaint the filename ... $filename = $LOGFILE{"UPDLOG"}."/".$YYMMDD; $filename =~ /(.*)/; $realfile = $1; # first let's log the updates send in or via stdin if (open(LOG, ">>$realfile")) { &lock(LOG); if ($opt_M) { print LOG "\n>>> MAIL UPDATE <<<\n\n"; } else { print LOG "\n>>> STDIN UPDATE <<<\n\n"; } open(TMP, "$TMPDIR/dbupdcopy.$$"); while (<TMP>) { print LOG; } close(TMP); close(LOG); &unlock(LOG); } else { &syslog("ERRLOG", "dbupdate cannot open $LOGFILE{\"UPDLOG\"}/$YYMMDD"); } # then we log the acknowledgement $filename = $LOGFILE{"ACKLOG"}."/".$YYMMDD; $filename =~ /(.*)/; $realfile = $1; if (open(LOG, ">>$realfile")) { &lock(LOG); if ($opt_M) { print LOG "\n>>> MAIL ACK <<<\n\n"; } else { print LOG "\n>>> STDIN ACK <<<\n\n"; } open(TMP, "$TMPDIR/dbupdack.$$"); while (<TMP>) { print LOG; } close(TMP); close(LOG); &unlock(LOG); } else { &syslog("ERRLOG", "dbupdate cannot open $LOGFILE{\"ACKLOG\"}/$YYMMDD"); } # remove the temp stuff we made unlink("$TMPDIR/dbtmp.$$"); unlink("$TMPDIR/dbupdcopy.$$"); unlink("$TMPDIR/dbupdack.$$"); -------- Logged at Wed Dec 14 12:21:49 MET 1994 ---------
[ rr-impl Archive ]