Summary: Looking for some help using a named pipe in my init.d startup script. The pipe doesn't work when it starts, and I can't figure out how to kill it.
I have this startup script that I'm using in Ubuntu 10.04 x64 to launch a minecraft server. The one thing that I need is to setup a read FIFO so that I can pass commands in to the server from the shell. I made a .fifo file and it works great if I launch the server manually from the shell as follows:
tail -f minecraft.fifo | /usr/lib/jvm/java-6-sun/bin/java -Xmx2048M -Xms2048M -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalPacing -XX:ParallelGCThreads=2 -XX:+AggressiveOpts -jar minecraft_server.jar &
Where I'm struggling is when I plug that tail -f minecraft.fifo in to the init script. When I start the service, the "tail -f minecraft.fifo" starts up; but it doesn't pass commands in to the minecraft server like it does when I start it manually from the shell.
Also, I'm not figuring out how to stop the named pipe. So far I figure I need to save the PID of the process and then kill that PID during stop. But I'm not figuring out how to get the PID out of $! in to a variable so that I can recall it.
Make sense? The tail doesn't work when I invoke it, and I'm not figuring out how to kill the tail process.
Here is the functioning startup script which does not contain the named pipe:
#!/bin/bash
# /etc/init.d/minecraft
### BEGIN INIT INFO
# Provides: minecraft
# Required-Start: $local_fs $remote_fs
# Required-Stop: $local_fs $remote_fs
# Should-Start: $network
# Should-Stop: $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Minecraft server
# Description: Starts the minecraft server
### END INIT INFO
#Settings
JARFILE='minecraft_server.jar'
USERNAME="minecraft"
MCHOME='/home/minecraft'
NAMEDPIPE='minecraft.fifo'
DAEMON="/usr/lib/jvm/java-6-sun/bin/java -Xmx2048M -Xms2048M -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalPacing -XX:ParallelGCThreads=2 -XX:+AggressiveOpts -jar $JARFILE nogui $"
ME=`whoami`
as_user() {
if [ $ME == $USERNAME ] ; then
bash -c "$1"
else
su - $USERNAME -c "$1"
fi
}
mc_start() {
if ps ax | grep -v grep | grep -v -i SCREEN | grep $JARFILE > /dev/null
then
echo "Tried to start but $JARFILE was already running!"
else
echo "$JARFILE was not running... starting."
cd $MCHOME
as_user "cd $MCHOME && screen -dmS minecraft $DAEMON"
sleep 7
if ps ax | grep -v grep | grep -v -i SCREEN | grep $JARFILE > /dev/null
then
echo "$JARFILE is now running."
else
echo "Could not start $JARFILE."
fi
fi
}
mc_stop() {
if ps ax | grep -v grep | grep -v -i SCREEN | grep $JARFILE > /dev/null
then
echo "$JARFILE is running... stopping."
as_user "screen -p 0 -S minecraft -X eval 'stuff \"say SERVER SHUTTING DOWN IN 10 SECONDS. Saving map...\"\015'"
as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-all\"\015'"
sleep 10
as_user "screen -p 0 -S minecraft -X eval 'stuff \"stop\"\015'"
sleep 7
else
echo "$JARFILE was not running."
fi
if ps ax | grep -v grep | grep -v -i SCREEN | grep $JARFILE > /dev/null
then
echo "$JARFILE could not be shut down... still running."
else
echo "$JARFILE is shut down."
fi
}
#Start-Stop here
case "$1" in
start)
mc_start
;;
stop)
mc_stop
;;
restart)
mc_stop
mc_start
;;
status)
if ps ax | grep -v grep | grep -v -i SCREEN | grep $JARFILE > /dev/null
then
echo "$JARFILE is running."
else
echo "$JARFILE is not running."
fi
;;
*)
echo "Usage: /etc/init.d/minecraft {start|stop|status|restart}"
exi开发者_运维技巧t 1
;;
esac
exit 0
If I modify the DAEMON variable as so, the script does start it, and the tail -f can be found with a ps -ef:
DAEMON="tail -f minecraft.fifo | /usr/lib/jvm/java-6-sun/bin/java -Xmx2048M -Xms2048M -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalPacing -XX:ParallelGCThreads=2 -XX:+AggressiveOpts -jar $JARFILE nogui $"
But if I echo a command to the minecraft.fifo, the server doesn't read it. Looking at the ps, it seems the tail -f minecraft.fifo is actually starting in a separate process. That may be the problem.
Note: I'm using the SCREEN command to invoke the DAEMON because I needed a way to jump in to a running server and issue commands to it. So I just screen -r as the user minecraft and then I can work with the server. Once this fifo is working, however, I will no longer need the screen stuff. So if that's getting in the way, it can be removed.
As for killing it; if I put a killall tail in the mc_stop, it works. But that kills all tails and I have others running that I don't want to kill. So far I haven't figured out how to start the server in a way that stores the PID so that I can kill using the PID. Or to start the tail with a unique process name so that I could killall it without endangering other tails.
Any thoughts on how to start the server properly using the named pipe; and then how to properly stop it?
Rather than using tail -f
, why not run a script monitoring the FIFO named pipe?
#!/bin/bash
NAMEDPIPE="/path/to/minecraft.fifo"
STOP_NOW="no"
STOP_SIGNAL="there is no place like home"
DELAY="1s"
while [[ $STOP_NOW == "no" ]]; do
read INCOMING_THINGS
if [[ $STOP_SIGNAL == "$INCOMING_THINGS" ]]; then
STOP_NOW="yes"
else
printf "%s\n" "$INCOMING_THINGS"
sleep $DELAY
fi
done < $NAMEDPIPE
exit 0
Test it using scriptname.sh
, and if it's to your liking, prime it with scriptname.sh | whatever_commands_here
. Or even nohup scriptname.sh | whatever_commands &
.
Send the signal there is no place like home\n
to the named pipe and scriptname.sh
should end gracefully.
(I hope I didn't misunderstand your problem.)
For sending commands to the server via a named pipe (fifo) from the shell see here:
Redirecting input of application (java) but still allowing stdin in BASH
How do I use exec 3>myfifo in a script, and not have echo foo>&3 close the pipe?
Ok I just facepalmed and realized that I don't need to use a fifo since I'm already using SCREEN to pass commands in to it through the mc_stop. (I didn't write the startup script, I'm just trying to tweak it, so not intimately familiar with it)
screen -p 0 -S minecraft -X eval 'stuff \"say SERVER SHUTTING DOWN IN 10 SECONDS. Saving map...\"\015'"
That accomplished exactly what I wanted to use the fifo for.
SO...mine was a stupid question. This issue is resolved.
@pepoluan; thanks very much for helping. I really appreciate the response. I did attempt to use the script and it worked, but it also did something very strange. It successfully sent the command to the fifo. But then it went in to a strange loop and sent some sort of null command to the server. The server recognized the first command and then started echoing "command not recognized". What command was not recognized is a mystery, as it isn't in the logs and did not display in the minecraft console. I will, however, continue working with your script so that I can further understand fifo's. I attempted to vote up your response in appreciate but stackexchange told me that I didn't have a high enough reputation yet. So if someone else could vote him up for me; please.
精彩评论