Here's a modified patch for Inotify2 support. It fixes a typo in Watch_Incoming() and also tests for the existence of Linux::Inotify2. I've also added some log messages to help with debugging.
-- Regards, Andres Mejia
diff -urN debpool_released/bin/debpool debpool/bin/debpool --- debpool_released/bin/debpool 2007-12-03 14:10:49.000000000 -0500 +++ debpool/bin/debpool 2007-12-13 04:03:38.000000000 -0500 @@ -118,26 +147,63 @@ die "$msg\n"; } +# Print the path set for the lockfile and exit. This is mainly used to run +# debpool with start-stop-daemon. + +if ($Options{'get_lock_path'}) { + print "$Options{'lock_file'}\n"; + exit 0; +} + # Obtain a lockfile. We should never run more than one occurance; it's too # likely that we'd step on our own toes. if (!sysopen(LOCK_FILE, $Options{'lock_file'}, O_WRONLY|O_CREAT|O_EXCL, 0644)) { - my($msg) = "Couldn't obtain lockfile '$Options{'lock_file'}'; "; + my($msg) = "Couldn't obtain lockfile '$Options{'lock_file'}': "; if (open(LOCK_FILE, '<', $Options{'lock_file'}) && (my($pid) = <LOCK_FILE>)) { chomp($pid); - $msg .= "(PID $pid)\n"; + if (open(STAT_FILE, '<', "/proc/$pid/stat") && + (my($stat) = <STAT_FILE>)) { + if ($stat =~ m/debpool/) { + # debpool process was already started + $msg .= "debpool was already running with PID $pid\n"; + close(LOCK_FILE); + close(STAT_FILE); + die $msg; + } + } else { + # debpool wasn't running using the specified PID so remove + # the lock and create a new one + close(LOCK_FILE); + unlink $Options{'lock_file'}; + sysopen(NEW_LOCK_FILE, $Options{'lock_file'}, + O_WRONLY|O_CREAT|O_EXCL, 0644); + print NEW_LOCK_FILE "$$\n"; + close(NEW_LOCK_FILE); + } } else { + # Could not read PID from lockfile $msg .= "(unable to read PID)\n"; } - - die $msg; -} else { # Do something useful - like put our PID into the file. +} else { # debpool wasn't running so create a lock print LOCK_FILE "$$\n"; close(LOCK_FILE); } +if ($Options{'daemon'} && $Options{'use_inotify'}) { + # Fall back to normal monitoring if Inotify setup fails. + if (!Setup_Incoming_Watch()) { + Log_Message("Not using inotify with debpool.", LOG_GENERAL, LOG_WARNING); + $Options{'use_inotify'} = 0; + } +} + +# Check for any changes files in the incoming directory. + +my(@changefiles) = Scan_Changes($Options{'incoming_dir'}); + # Start the main loop. We use a do/until loop so that we always fire off at # least once. @@ -163,10 +229,6 @@ } } -# Check for any changes files in the incoming directory. - -my(@changefiles) = Scan_Changes($Options{'incoming_dir'}); - # Go through each of the changes files we found, and process it. This is the # heart of things. @@ -640,7 +700,8 @@ if ($Options{'daemon'}) { Log_Message("Waiting on changes to incoming dir.", LOG_GENERAL, LOG_DEBUG); - if (!Monitor_Incoming()) { + @changefiles = Monitor_Incoming(); + if ([EMAIL PROTECTED] && !$Signal_Caught) { my($msg) = "Error in Monitor_Incoming: " . $DebPool::Dirs::Error; Log_Message($msg, LOG_GENERAL, LOG_ERROR); } diff -urN debpool_released/share/DebPool/Config.pm debpool/share/DebPool/Config.pm --- debpool_released/share/DebPool/Config.pm 2007-12-03 14:10:49.000000000 -0500 +++ debpool/share/DebPool/Config.pm 2007-12-13 04:03:55.000000000 -0500 @@ -865,6 +897,17 @@ $Options{'sleep'} = 300; $OptionDefs{'sleep'} = 'sleep=i'; +=item B<use_inotify> = I<boolean> + +Sets whether debpool should use inotify to monitor for incoming changes + +Default value: 0 (false) + +=cut + +$Options{'use_inotify'} = 0; +$OptionDefs{'use_inotify'} = 'use_inotify!'; + =item B<rollback> = I<boolean> This determines whether older packages in the incoming queue are allowed diff -urN debpool_released/share/DebPool/Dirs.pm debpool/share/DebPool/Dirs.pm --- debpool_released/share/DebPool/Dirs.pm 2007-12-03 14:10:49.000000000 -0500 +++ debpool/share/DebPool/Dirs.pm 2007-12-13 04:04:10.000000000 -0500 @@ -60,6 +60,8 @@ @EXPORT_OK = qw( &Archfile &Create_Tree + &Tree_Mkdir + &Setup_Incoming_Watch &Monitor_Incoming &PoolBasePath &PoolDir @@ -69,7 +71,8 @@ ); %EXPORT_TAGS = ( - 'functions' => [qw(&Archfile &Create_Tree &Monitor_Incoming + 'functions' => [qw(&Archfile &Create_Tree &Tree_Mkdir + &Monitor_Incoming &Setup_Incoming_Watch &PoolBasePath &PoolDir &Scan_Changes &Scan_All &Strip_Subsection)], 'vars' => [qw()], @@ -87,6 +90,8 @@ our($Error); +my($inotify); + ### File lexicals # None @@ -313,10 +309,70 @@ return [EMAIL PROTECTED]; } +# Setup_Incoming_Watch() +# +# Creates a Linux::Inotify2 object and adds a watch on the incoming directory. +# Returns 1 on success, 0 on failure (and sets $Error). + +sub Setup_Incoming_Watch { + use DebPool::Logging qw(:functions :facility :level); + use DebPool::Config; + if (!eval{ require Linux::Inotify2; }) { + Log_Message("liblinux-inotify2-perl is required to activate inotify support for debpool.", LOG_GENERAL, LOG_WARNING); + return 0; + } else { + use Linux::Inotify2; + } + + $inotify = new Linux::Inotify2; + if (!$inotify) { + $Error = "Unable to create new inotify object: $!"; + Log_Message("$Error", LOG_GENERAL, LOG_ERROR); + return 0; + } + if (!$inotify->watch("$Options{'incoming_dir'}", + IN_CLOSE_WRITE | + IN_MOVED_TO )) { + $Error = "Unable to watch $Options{'incoming_dir'}: $!"; + Log_Message("$Error", LOG_GENERAL, LOG_ERROR); + return 0; + } + Log_Message("Watching $Options{'incoming_dir'} with Inotify", + LOG_GENERAL, LOG_DEBUG); + return 1; +} + +# Watch_Incoming() +# +# Reads events from the Inotify2 object (blocking until one occurs), +# picks out the .changes file(s) and returns them (if any; otherwise +# it loops). +# +# Returns a list of .changes files on success, undef on failure (which +# includes interruption by a signal). + +sub Watch_Incoming { + use DebPool::Logging qw(:functions :facility :level); + + while (my @events = $inotify->read) { + my @changes; + foreach (@events) { + push @changes, $_->name if ($_->name =~ /\.changes$/); + } + if (@changes > 0) { + Log_Message("Found changes: ".join(', ', @changes), + LOG_GENERAL, LOG_DEBUG); + return @changes; + } + } + return undef; +} + # Monitor_Incoming() # # Monitors the incoming directory, looping until the directory is updated. -# Returns 1 on success, 0 on failure (and sets $Error). +# Returns a list of .changes files on success, undef on failure (which +# includes interruption by a signal - check $DebPool::Signal::Signal_Caught). sub Monitor_Incoming { use DebPool::Config; @@ -327,28 +383,29 @@ # further. if ($DebPool::Signal::Signal_Caught) { - return 1; + return undef; } - my(@stat) = stat($Options{'incoming_dir'}); - if ([EMAIL PROTECTED]) { - $Error = "Couldn't stat incoming_dir '$Options{'incoming_dir'}'"; - return 0; - } - my($mtime) = $stat[9]; - - do { - Log_Message("Incoming monitor: sleeping for " . - $Options{'sleep'} . " seconds", LOG_GENERAL, LOG_DEBUG); - sleep($Options{'sleep'}); - @stat = stat($Options{'incoming_dir'}); - if ([EMAIL PROTECTED]) { - $Error = "Couldn't stat incoming_dir '$Options{'incoming_dir'}'"; - return 0; - } - } until (($stat[9] != $mtime) || ($DebPool::Signal::Signal_Caught)); + if ($Options{'use_inotify'}) { + return Watch_Incoming(); + } else { + my(@stat) = stat($Options{'incoming_dir'}); + my($mtime) = $stat[9]; - return 1; + do { + Log_Message("Incoming monitor: sleeping for " . + $Options{'sleep'} . " seconds", LOG_GENERAL, LOG_DEBUG); + sleep($Options{'sleep'}); + @stat = stat($Options{'incoming_dir'}); + if ([EMAIL PROTECTED]) { + $Error = "Couldn't stat incoming_dir '$Options{'incoming_dir'}'"; + return undef; + } + return undef if $DebPool::Signal::Signal_Caught; + } until ($stat[9] != $mtime); + + return Scan_Changes(); + } } # PoolDir($name, $section, $archive_base)