Package: getmail6 Version: 6.18.13-1 Severity: minor Since upgrading from getmail6 6.18.11-2 to 6.18.13-1, I've been getting this warning whenever getmail delivers a message: handler called, but no children
The message comes from the ForkingBase class, whose signal handler is getting called for a SIGCHLD other than from the expected child. Then the expected SIGCHLD comes and is handled, waking up _wait_for_child(). I've attached a test case showing the problem. Run as follows: cd getmailtest socat TCP6-LISTEN:1110,fork EXEC:./pop3 & getmail -g cfg/ I guess ForkingBase only exists to handle the "user" option, which I'm not using. Otherwise, forking would be unnecessary or could be handled by Python's subprocess module--and as of Python 3.9, that module can do the setreuid() and setregid() calls too. It also supports a timeout, which is the only justification I can see for messing around with the process's SIGCHLD handler (if not for that, a simple waitpid() would work). Given that no timeout seems to be documented for filter and destination classes, and it could cause problems for people not expecting it, I'm inclined to call that a bug. I've attached a patch that gets rid of the handler and its timeout. ( To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this work to the public domain worldwide. See https://creativecommons.org/publicdomain/zero/1.0/legalcode ) I've done only trivial testing on the patched version. As hinted above, a cleaner fix would be to delete all this code and use the subprocess module (or os.seteuid() and such for cases not requiring a sub-process). - Michael -- System Information: Debian Release: trixie/sid APT prefers unstable-debug APT policy: (500, 'unstable-debug'), (500, 'unstable'), (1, 'experimental') Architecture: amd64 (x86_64) Kernel: Linux 6.6.15-amd64 (SMP w/32 CPU threads; PREEMPT) Locale: LANG=en_CA.UTF-8, LC_CTYPE=en_CA.UTF-8 (charmap=UTF-8), LANGUAGE=en_CA:en Shell: /bin/sh linked to /usr/bin/dash Init: systemd (via /run/systemd/system) LSM: AppArmor: enabled Versions of packages getmail6 depends on: ii python3 3.11.6-1 getmail6 recommends no packages. getmail6 suggests no packages. -- no debconf information
getmailtest.tar.gz
Description: Binary data
diff --git a/getmail b/getmail index 58ad52b0353e..821cfb22f579 100755 --- a/getmail +++ b/getmail @@ -643,6 +643,8 @@ No other entry is `Unseen`, i.e. `-s,` means `imap_search,imap_on_delete=Unseen, s += '%s="%s"' % (attr, pprint.pformat(getattr(options, attr))) log.debug('parsed options: %s\n' % s) + signal.signal(signal.SIGCHLD, signal.SIG_DFL) + imap_override = {} flags,search = imap_search_flags(options.override_imap) if flags: diff --git a/getmailcore/baseclasses.py b/getmailcore/baseclasses.py index cc2ed948c59d..d081926de25d 100755 --- a/getmailcore/baseclasses.py +++ b/getmailcore/baseclasses.py @@ -403,60 +403,28 @@ class ForkingBase(object): log - an object of type getmailcore.logging.Logger() ''' - def _child_handler(self, sig, stackframe): - def notify(): - self.__child_exited.acquire() - self.__child_exited.notify_all() - self.__child_exited.release() - self.log.trace('handler called for signal %s' % sig) + + def _wait_for_child(self, child_pid): try: - pid, r = os.waitpid(self.child.childpid,0) + pid, status = os.waitpid(child_pid, 0) except OSError as o: - # No children on SIGCHLD. Can't happen? - self.log.warning('handler called, but no children (%s)' % o) - notify() + self.log.warning('waitpid() failed (%s)' % o) return - if self.__orig_handler: - signal.signal(signal.SIGCHLD, self.__orig_handler) - self.__child_pid = pid - self.__child_status = r - self.log.trace('handler reaped child %s with status %s' % (pid, r)) - notify() - - def _prepare_child(self): - self.log.trace('') - self.__child_exited = Condition() - self.__child_pid = 0 - self.__child_status = None - self.__orig_handler = None - self.__orig_handler = signal.signal(signal.SIGCHLD, self._child_handler) - - def _wait_for_child(self, childpid): - self.__child_exited.acquire() - if self.__child_exited.wait(socket.getdefaulttimeout() or 60) == False: # py2, <py3.2: always None - raise getmailOperationError('waiting child pid %d timed out' - % childpid) - self.__child_exited.release() - if self.__child_pid != childpid: - #self.log.error('got child pid %d, not %d' % (pid, childpid)) - raise getmailOperationError( - 'got child pid %d, not %d' - % (self.__child_pid, childpid) - ) - if os.WIFSTOPPED(self.__child_status): + + if os.WIFSTOPPED(status): raise getmailOperationError( 'child pid %d stopped by signal %d' - % (self.__child_pid, os.WSTOPSIG(self.__child_status)) + % (child_pid, os.WSTOPSIG(status)) ) - if os.WIFSIGNALED(self.__child_status): + if os.WIFSIGNALED(status): raise getmailOperationError( 'child pid %d killed by signal %d' - % (self.__child_pid, os.WTERMSIG(self.__child_status)) + % (child_pid, os.WTERMSIG(status)) ) - if not os.WIFEXITED(self.__child_status): + if not os.WIFEXITED(status): raise getmailOperationError('child pid %d failed to exit' - % self.__child_pid) - exitcode = os.WEXITSTATUS(self.__child_status) + % child_pid) + exitcode = os.WEXITSTATUS(status) return exitcode def _pipemail(self, msg, delivered_to, received, unixfrom, stdout, stderr): @@ -485,7 +453,6 @@ class ForkingBase(object): child.stderr = TemporaryFile23() child.childpid = os.fork() if child.childpid != 0: # here (in the parent) - self._prepare_child() self.log.debug('spawned child %d\n' % child.childpid) child.exitcode = self._wait_for_child(child.childpid) child.stderr.seek(0)
signature.asc
Description: PGP signature