LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   BASH scripting, creating a custom service (CentOS) (http://www.linuxquestions.org/questions/programming-9/bash-scripting-creating-a-custom-service-centos-879313/)

r3sistance 05-07-2011 05:37 AM

BASH scripting, creating a custom service (CentOS)
 
I am trying to create a custom service to manage a minecraft server what runs in a screen session (this is to allow easy console access as opposed to running it as a nohup background process). I am hitting two main issues with this script so far and wondering if anybody is able to shed some light on it, considering I am far from the greatest BASH scripter on Earth.

The issues are related to start and stop. the first issue with start is there is a command run "screen -dmS minecraft java -Xms1024M -Xmx1024M -jar /minecraft/minecraft.jar nogui" what doesn't appear to work, however when run from console (copy and pasted) this command seems to run perfectly. I am uncertain as to why this is not working within the script. Also if run from a script in /minecraft it also appears to work but in the minecraftd script I have created at /etc/init.d it does not work. I think the issue might be related to the location but am not certain on it, nor how to resolve it.

the second issue with stop is that it works sometimes but at other times it does not, overall it seems to work about 30~50% of the time. When it works it passes a couple of disconnection messages to the screen session and then gives the stop command (the command to gracefully terminate the minecraft server). It seems to work more often when using screen that I attach to the minecraft session while it is running but really not sure if this is an issue with my scripting or an issue with how I am passing things to screen.

The full code in /etc/init.d/minecraftd is below

Code:

#!/bin/bash
## Script Information
## Script Author: Berwick East
## Script Version: --------
## Last Updated: 07-MAY-2011

## Note
## this script is only a free service management tool for minecraft and can be redistribed, Minecraft itself however is not as per copyrights
## (http://www.minecraft.net/copyright.jsp).

##http://it.megocollector.com/?p=805

SERVICE="Minecraft"
RETVAL=0
PROCESS=`ps aux | grep minecraft | egrep -v 'SCREEN|grep|etc/init.d|service'`

start()
{
        if [ -z "$PROCESS" ]
        then
                cd /minecraft
                service iptables restart > /dev/null
                echo "$SERVICE is being started"
                iptables -I RH-Firewall-1-INPUT -p tcp --dport 25565 -j ACCEPT
                screen -dmS minecraft java -Xms1024M -Xmx1024M -jar /minecraft/minecraft.jar nogui
        else
                echo "$SERVICE appears to already be running"
        fi
}

stop()
{
        if [ "$PROCESS" ]
        then
                echo "$SERVICE is now sending disconnection messages"
                screen -d minecraft > /dev/null
                echo "sending first disconnect message (60 seconds left)"
                screen -S minecraft -X stuff $'say Server is preparing to shutdown in 60 seconds please disconnect.\n'
                sleep 30
                echo "sending second disconnect message (30 seconds left)"
                screen -S minecraft -X stuff $'say Server will shutdown in 30 seconds, disconnect immediately.\n'
                sleep 20
                echo "sending final disconnect message (10 seconds left)"
                screen -S minecraft -X stuff $'say Server is about to shutdown, you will be automatically disconnected in 10 seconds.\n'
                screen -S minecraft -X stuff $'stop\n'
                service iptables restart > /dev/null
                echo "$SERVICE is now stopping"
                sleep 20
                RETEST=`ps aux | grep minecraft | egrep -v 'SCREEN|grep|etc/init.d|service'`
                if [ "$RETEST" ]
                then
                        echo "$SERVICE failed to stop in expected time, please enter 'screen -r minecraft' into the console and then enter 'STOP' manually."
                        exit 1
                else
                        echo "$SERVICE stopped successfully"
                fi
        else
                echo "$SERVICE not found, if running please kill manually"
                exit 1
        fi

}

status()
{
##http://www.anyexample.com/linux_bsd/bash/check_if_program_is_running_with_bash_shell_script.xml
        if [ "$PROCESS" ]
        then
            echo "$SERVICE is running"
        else
            echo "$SERVICE is stopped"
        fi

}

restart()
{
        if [ "$PROCESS" ]
        then
                stop
        else
                echo "$SERVICE was already stopped"
        fi

        start
}

case $1 in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
status)
status
;;
*)
echo $"Usage: $0 {start|stop|restart|status}"
exit 1
esac
exit $RETVAL

Any help would be appreciated,
Thanks in advanced.

carltm 05-07-2011 09:41 AM

A couple of thoughts. Red Hat/Centos has it's own way of managing
services. To see a good example, look at /etc/init.d/crond. Notice
that it has several commented lines starting with the keyword chkconfig.
These are required to properly use the service management tools, ntsysv
and chkconfig. It's a good idea to start with this as a template and
update it to match your new service. It's more work, but it ensures
that your service will be compatible with the OS.

Second thought. I'll bet the issue with it not starting is that bash
knows whether or not it is being run interactively, and screen is
expecting to be run from an interactive shell. What's the difference?
In an interactive shell your keyboard is set up as input and output
goes to your display (unless redirected). In a non-interactive shell
there is no input and output is buffered (unless redirected). I hope
this makes sense.

r3sistance 05-07-2011 11:23 AM

I'll look into configuring it to the template once I have things working (don't want it to be for nothing if I still can't get it working).

I am not sure I get the issue with interactive mode, I mean I can understand that when you run a script file it runs it in a separate shell, however in another script where I have copied and pasted the exact line from, it works fine, so I am not sure why it'd have that problem with one script file and not another. expect for testing I always start this process via script.

carltm 05-07-2011 02:08 PM

When you start a shell interactively, it assumes that the input
is coming from a keyboard and output is going to a screen. When
it is started non-interactively (either in a startup script or
an at or cron job), it assumes there is no keyboard and that the
output is not being seen in real time by a human. So it's all
about input and output. Let me know if this still doesn't make
sense.

Some programs such as sudo check to see if the shell is interactive.
I'll bet that screen does such a check and it is refusing to run.

Try searching for "linux screen non-interactive shell" and see
if it sheds any light.

carltm 05-07-2011 02:16 PM

Just to follow up on your last sentence. Any time you run a script
it starts in a shell (unless you use the . command). It's the parent
shell that is important here. When you type the command, the parent
shell is an interactive bash shell. When the command is run as a
service, the parent shell is a non-interactive shell launched by
the startup scripts.

Basically it's not a question of how the script was written, it's
a question of whether or not the invoking shell is interactive.

There may be a work around for this by adding some parameter to
screen. Try the search from my last reply.

theNbomr 05-08-2011 01:38 AM

You can start screen without a controlling terminal, in detached mode. Then you have to use the '-X stuff' command to stuff characters into the detached session, and you can do that from your script, once you've launched screen. . I use this method quite a bit to start processes that have an interactive aspect to them, and to which I want to later attach and do interactive stuff.

--- rod.

r3sistance 05-08-2011 01:55 AM

Thanks Carl,

I noticed this last night but had to go to sleep, I think I have a few ideas of where I need to look. Thank you.

theNbomr,

The Screen session already starts in detached mode, it uses -dmS and uses stuff already :).

r3sistance 05-08-2011 07:24 AM

Ok I have figured out all of my issues. Thank you carltm, while your suspicious appears to have been wrong you put me in the right mind set to figure this all out and I thank you for that!

I have figured out what is causing the stop issue and have resolved it dirtily. The screen session will only close if I have attached to it (via screen -r minecraft) either before or during the shut down, if I have never attached to the screen session it will not run, I have already found one thread on this and after reading this I had a brainstorm. From that I have figured out my own method, a second screen session that attaches to the first, this appears to work. The code now looks like

Code:

stop()
{
        if [ "$PROCESS" ]
        then
                screen -dms dirtyhack screen -r minecraft
                echo "$SERVICE is now sending disconnection messages"
                screen -d minecraft > /dev/null
                echo "sending first disconnect message (60 seconds left)"
                screen -S minecraft -X stuff $'say Server is preparing to shutdown in 60 seconds please disconnect.\n'
                sleep 30
                echo "sending second disconnect message (30 seconds left)"
                screen -S minecraft -X stuff $'say Server will shutdown in 30 seconds, disconnect immediately.\n'
                sleep 20
                echo "sending final disconnect message (10 seconds left)"
                screen -S minecraft -X stuff $'say Server is about to shutdown, you will be automatically disconnected in 10 seconds.\n'
                screen -S minecraft -X stuff $'stop\n'
                service iptables restart > /dev/null
                echo "$SERVICE is now stopping"
                sleep 20
                RETEST=`ps aux | grep minecraft | egrep -v 'SCREEN|grep|etc/init.d|service'`
                if [ "$RETEST" ]
                then
                        echo "$SERVICE failed to stop in expected time, please enter 'screen -r minecraft' into the console and then enter 'STOP' manually."
                        exit 1
                else
                        echo "$SERVICE stopped successfully"
                fi
        else
                echo "$SERVICE not found, if running please kill manually"
                exit 1
        fi

}

As for the start script, I never thought to try the script by doing "/etc/init.d/minecraftd start"! This method works so it very much appears that service is responsible for it not running. The problem can only be made more confusing however, the above stop routine also creates a screen session in very much the same way but this works fine by running service.

My suspicious became that service does not use the same path as the user that calls it and since when I installed java I only made the path for root I simpled switched "java" for the route to where java is actually held and that works. So this appears all solved, but if anybody has any cleaner way to handle the attach issue for the stop script I would like to hear it.

it appears Service has the path "/sbin:/usr/sbin:/bin:/usr/bin", what is definitely not the same as I have configure for root and thus my prolbem, Java does not exist in any of these, I will probably symbolic link java to /sbin now (probably crossing partitions but allows me to write the code a bit neater).

carltm 05-08-2011 08:42 AM

Glad to hear that you've got it working.

There are many ways to handle paths. My suggestion would be
to export the path that you need from inside the startup
script. Doing it this way will prevent surprises later if
you install another instance of java or if a security update
makes some change to the default version of java. Just add
a line like this.

Code:

export PATH=$PATH:/path/to/java/bin:/any/other/required/path

theNbomr 05-08-2011 11:28 AM

You can probably get around the 'screen in screen' method by using the -p 0 option in your command that stuffs strings into the detached screen.
--- rod.


All times are GMT -5. The time now is 08:51 AM.