June 11, 201214 yr I am (was?) just about to announce/release a plugin for the Dovecot mailserver. However, in my pre-release testing I've discovered an oddity and I wonder whether anyone is able to cast any light. I can start/stop etc the Dovecot server using the command /etc/rc.d/rc.dovecot start (stop etc.) from the command line, and everything performs well. The command prompt returns immediately in every case. However, when I start Dovecot from the emhttp plugin page, the browser page does not redraw (it's left displaying 'Starting Dovecot:' and 'Dovecot started'). I also find that ps -eaf shows the rc.dovecot process as <defunct>. In this state, Dovecot fails to respond to connections from mail clients. The same problem applies to the enable action (which also invokes start). All other actions from the emhttp control page respond exactly as expected, and the page is redrawn within less than a second. I have to believe that I'm missing something very obvious. Can any one spot the fault? My rc.dovecot: #!/bin/sh # Start/stop/reload/enable/disable dovecot. dovecot_start() { # no-op if not enabled if [ $SERVICE != "enable" ]; then return fi # no-op if already running if [ -r /usr/local/var/run/dovecot/master.pid ]; then return fi echo "Starting dovecot:" /usr/local/sbin/dovecot echo "Dovecot started" echo } dovecot_stop() { # no-op if not running if [ ! -r /usr/local/var/run/dovecot/master.pid ]; then return fi echo -n "Stopping dovecot..." /usr/local/sbin/dovecot stop echo } dovecot_reload() { echo -n "Reloading dovecot configuration..." /usr/local/sbin/dovecot reload echo } write_config() { echo "# dovecot configuration" > /boot/config/plugins/dovecot/dovecot.cfg echo "SERVICE=\"$SERVICE\"" >> /boot/config/plugins/dovecot/dovecot.cfg } dovecot_enable() { # if not already enabled, enable it if [ "$SERVICE" != "enable" ]; then SERVICE=enable write_config fi # Copy private configuration file if [ ! -e "/usr/local/etc/dovecot/dovecot.conf" ]; then cp /boot/config/plugins/dovecot/dovecot.conf /usr/local/etc/dovecot/ fi # enabling also starts it dovecot_start } dovecot_disable() { dovecot_stop SERVICE=disable write_config } # read our configuration source /boot/config/plugins/dovecot/dovecot.cfg case "$1" in 'start') dovecot_start ;; 'stop') dovecot_stop ;; 'reload') dovecot_reload ;; 'enable') dovecot_enable $2 ;; 'disable') dovecot_disable ;; *) echo "usage $0 start|stop|reload|enable|disable" esac My dovecot.php: <?PHP $dovecot_cfg = parse_ini_file( "/boot/config/plugins/dovecot/dovecot.cfg"); $dovecot_running = file_exists( "/usr/local/var/run/dovecot/master.pid") ? "yes" : "no"; ?> <!-- When this form is submitted, emhttp will see a GET request like this: "GET /update.htm?cmd=/etc/rc.d/rc.dovecot&arg1=enable&arg2=/usr/local/dovecot&runCmd=Apply" (Actually arg1 can be 'enable' or 'disable' and arg2 is the directory in the form box, provided the field is not disabled.) The 'runCmd=Apply' tells emhttp to run the command given by 'cmd' with arguments 'arg1', 'arg2', ... In this case it will run: "/etc/rc.d/rc.dovecot enable /usr/local/dovecot" The output of this command will show up in the 'progress frame' of the webpage. We have thus constructed the form to control dovecot via the rc.dovecot script. --> <? if ($dovecot_cfg['SERVICE'] == "disable"): ?> <p class=ContentTitle>Dovecot Mail Server is disabled</p> <? else: ?> <? if ($dovecot_running!="yes"): ?> <p class=ContentTitle>Dovecot Mail Server is stopped</p> <? else: ?> <p class=ContentTitle>Dovecot Mail Server is running</p> <? endif; ?> <? endif; ?> <form name="dovecot_settings" method="POST" action="/update.htm" target="progressFrame"> <input type="hidden" name="cmd" value="/etc/rc.d/rc.dovecot"> <table class="settings"> <tr> <td>Action :</td> <td><select name="arg1" size="1"> <? if ($dovecot_cfg['SERVICE'] == "disable"): ?> <option value="enable">enable</option> <? else: ?> <? if ($dovecot_running != "yes"): ?> <option value="disable">disable</option> <option value="start">start</option> <? else: ?> <option value="stop">stop</option> <option value="reload">reload</option> <? endif; ?> <? endif; ?> </select></td> <tr><td></td> <td><input type="submit" name="runCmd" value="Apply"> <button type="button" onClick="done();">Done</button> </td></tr> </table> </form> <hr>
June 11, 201214 yr Author A little more info which may, or may not, be relevant. Dovecot starts perfectly well from the disks_mounted event handler (which simply calls '/etc/rc.d/rc.dovecot start' from a bash script). Dovecot doesn't always fail to respond to client connections when started from the emhttp page (but I'm not sure why/when), even though the page fails to reload. If Dovecot fails to complete its startup, but reports an error such as a missing configuration file, then the web page reloads correctly. The defunct rc.dovecot process goes away as soon as I cancel the browser fetch/redraw, but the defunct process cannot be killed by kill -9.
June 11, 201214 yr The defunct rc.dovecot process goes away as soon as I cancel the browser fetch/redraw, but the defunct process cannot be killed by kill -9. Defunct processes are those that HAVE ALREADY TERMINATED. They may not be killed, as they are already dead. They are simply waiting for their parent process to handle their exit status. (In the case of a defunct process, the parent may not have issued a "wait" to capture the exit status of the child process) See here: http://en.wikipedia.org/wiki/Zombie_process
June 11, 201214 yr Author The defunct rc.dovecot process goes away as soon as I cancel the browser fetch/redraw, but the defunct process cannot be killed by kill -9. Defunct processes are those that HAVE ALREADY TERMINATED. They may not be killed, as they are already dead. They are simply waiting for their parent process to handle their exit status. (In the case of a defunct process, the parent may not have issued a "wait" to capture the exit status of the child process) See here: http://en.wikipedia.org/wiki/Zombie_process Ah, okay - I've seen zombie processes in the process table ... I hadn't realised that defunct was the same. I wonder why there are two different terms, and what determines which term will be used. So, is this occurring because of a fault in my plugin code, or is there a problem in emhttp? Any idea how I can work round it?
June 11, 201214 yr Hi, I had the similar problem with plex, but after I redirect the output to /dev/null it works. Maybe you give it a try. /usr/local/sbin/dovecot > /dev/null &
June 11, 201214 yr Author Hi, I had the similar problem with plex, but after I redirect the output to /dev/null it works. Maybe you give it a try. /usr/local/sbin/dovecot > /dev/null & Thank you for your reply, and the suggestion. Unfortunately, redirecting output doesn't have any effect on my problem. I would have been surprised if it did because the dovecot process does not output anything to the terminal when it is invoked manually.
June 11, 201214 yr Author (In the case of a defunct process, the parent may not have issued a "wait" to capture the exit status of the child process) Okay, following this suggestion, I inserted a 'sleep 5' after the invocation of dovecot. This had no effect. I then changed this to a 'wait', which also had no effect. See here: http://en.wikipedia.org/wiki/Zombie_process This suggests a 'kill -SIGCHLD pid' on the parent process (emhttp), but this has no effect either. Further thought suggests that emhttp is waiting - that is why the web page doesn't get re-drawn. I did try putting an 'exit 0' in rc.dovecot but this, of course, has no effect since the process is already terminated (else it wouldn't be defunct). However, if I stop Dovecot from the command line, then the web page does redraw. I'm not sure that I understand why, since Dovecot is a grandchild of emhttp, and the child (rc.dovecot) has already terminated. However, it does seem that emhttp is waiting for the grandchild to terminate, for some reason - I don't understand why, and I don't know how to get around this.
June 11, 201214 yr Author Again, I really didn't expect it to help, but I added another generation by making rc.dovecot call another script which invokes the dovecot binary. My expectation wasn't disappointed!
June 11, 201214 yr Author I still don't understand why .... but the solution is to 'sudo /usr/local/sbin/dovecot'. I'm convinced that dovecot doesn't require su in order to startup and run but, somehow, the 'sudo' allows emhttp to recognise when the child has terminated. Ah well, I'm almost ready to announce .....
June 12, 201214 yr Hi, I had the similar problem with plex, but after I redirect the output to /dev/null it works. Maybe you give it a try. /usr/local/sbin/dovecot > /dev/null & Thank you for your reply, and the suggestion. Unfortunately, redirecting output doesn't have any effect on my problem. I would have been surprised if it did because the dovecot process does not output anything to the terminal when it is invoked manually. Did you try re-directing BOTH stdout AND stderr output? /usr/local/sbin/dovecot > /dev/null 2>&1 & Did you try disowning the dovecot process you put in the background? disown %% Joe L.
April 12, 201313 yr I had this exact same problem, but wrote my rc script in Python. I tried PeterB's "sudo" trick but had no luck, what ended up working for me was doing both "sudo" and setting an open file pointed to /dev/null to stdin, stdout and stderr (passing None didn't work). Like so: devnull = open('/dev/null', 'w') subprocess.Popen(["sudo", "/usr/bin/python", "/path/to/plugin/file.py", stdin=devnull, stdout=devnull, stderr=devnull)
Archived
This topic is now archived and is closed to further replies.