Advertisement
Guest User

starbinder.sh

a guest
Feb 9th, 2014
385
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 30.91 KB | None | 0 0
  1. #!/bin/bash
  2. #
  3. # Starbinder: A StarBound game server control system.
  4. # v20140208.2214
  5. #
  6.  
  7. PATH=/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin
  8. AVAIL_ACTIONS="start|stop|restart|status|list|update|update-validate|console|install|relink|delink|lockdown-master|unlock-master|bootstrap"
  9. AVAIL_ACTIONS1="list|update|update-validate|lockdown-master|unlock-master|bootstrap"
  10. AVAIL_ACTIONS2="start|stop|restart|status|console|install|relink|delink"
  11.  
  12. MYNAME=$(basename $0)
  13. RUNUSER=$(whoami)
  14. IN_ACTION="$1"
  15. IN_SERVNAME="$2"
  16. # INSTALL_PREFIX=""
  17. INSTALL_PREFIX="starbound-"
  18. #
  19. # If IN_SERVNAME has any trailing slashes, due to shell autocompletion, remove it
  20. if (echo "$IN_SERVNAME" | egrep "*/$" &> /dev/null) ; then
  21.     echo "NOTE: Trimming target trailing slash on input."
  22.     IN_SERVNAME=$(echo "$IN_SERVNAME" | tr -d /)
  23. fi
  24. # If an INSTALL_PREFIX has been set, preprend it to input if not included, for user convinience.
  25. if [[ -n "$INSTALL_PREFIX" ]] ; then
  26.     if ! ( echo "$IN_SERVNAME" | egrep "^$INSTALL_PREFIX" ) ; then
  27.         SERVNAME=${INSTALL_PREFIX}${IN_SERVNAME}
  28.     else   
  29.         SERVNAME=$IN_SERVNAME
  30.     fi
  31. fi
  32.  
  33. MAILER=/usr/bin/mail
  34. MAILTO=asdf@asdf.com
  35. MAILNOTIFY=no
  36.  
  37. STEAMCMD_DIR=~/bin/steamcmd
  38. STEAMCMD_BIN=$STEAMCMD_DIR/steamcmd.sh
  39. STEAMCMD_SERVER_APPID=211820
  40. STEAMCMD_USER=""
  41. STEAMCMD_PASSWD=""
  42.  
  43. APPDIR=~/starbinder
  44. # APPDIR=/srv/starbinder
  45.  
  46. MASTER_INSTALLID=starbound-MASTER
  47. APPBIN=starbound_server
  48. BINDIR=$APPDIR/$SERVNAME/linux64
  49. SBCFGFILE=$APPDIR/$SERVNAME/starbound.config
  50. LOCKFILE=$APPDIR/$MASTER_INSTALLID/lockfile.lock
  51. PIDFILE=$APPDIR/$SERVNAME/running.pid # Also set in f_getpid
  52. NICECMD="nice -n 11 ionice -c 2 -n 6"
  53.  
  54. # --
  55.  
  56. f_cleanuptrap() {
  57.     # Cleanup trap.
  58.     echo ""
  59.     echo "Cleaning up..."
  60.     # Remove the update lock file, if we need to, and if it is there.
  61.     if [[ "$UPDATING" == 1 ]] ; then
  62.         [[ -f "$LOCKFILE" ]] && rm -f "$LOCKFILE"
  63.     fi
  64.     echo "Done."
  65.     echo ""
  66.     exit 90
  67. }
  68.  
  69. f_getpid() {
  70.     # Get the current PID of the running server.
  71.     PIDFILE=$APPDIR/$SERVNAME/running.pid # required for loops.
  72.     if [[ -r "$PIDFILE" ]] ; then
  73.         SERVPID=$(cat $PIDFILE)
  74.         SERVSTATUS="running"
  75.         # Test for crashed/broken servers by checking for a valid running process.
  76.         if [[ -n "$SERVPID" ]] && [[ -z "$(ps --no-headers -p $SERVPID -o pid)" ]] ; then
  77.             echo ""
  78.             echo "ERROR: Found server PIDFILE with PID $SERVPID, but process is missing."
  79.             echo "The server may have crashed or was shut down improperly, without reaping the PIDFILE."
  80.             echo "We will now stop the server, which will prevent any further damage and clean up this mess."
  81.             rm -f "$PIDFILE" || { echo "PANIC!" ; exit 1 ; } #The PIDFILE is junk, so delete it. If this wasn't here, infinite loop.
  82.             f_stop ; exit 1
  83.         fi
  84.     else
  85.         SERVPID=""
  86.         SERVSTATUS="stopped"
  87.     fi
  88. }
  89.  
  90. f_bootstrap() {
  91.     # First-time installation of the master install, checking for dependancies, and other basic setup.
  92.     echo ""
  93.     echo "We will now attempt to do the basic setup needed to get $MYNAME up and running."
  94.     echo ""
  95.     #
  96.     # Dependancy checks.
  97.     echo "$MYNAME requires a number of dependancies to run. We will check for them now..."
  98.     echo "NOTE: We do not bother to check for certain core utilities, such as shell built-ins, mkdir, et-cetera."
  99.     echo ""
  100.     echo "VERIFICATION: Shall we continue?"
  101.     read -e -r -p "y/N: " -i "" REPLY
  102.     if [[ ! "$REPLY" == [yY] ]]; then
  103.         echo ""
  104.         echo "Quitting."
  105.         echo ""
  106.         exit 0
  107.     fi
  108.     for EACH in lns symlinks sudo tmux renice kill lsof egrep mail chown chmod ; do
  109.         DEP_FILE=$(which $EACH)
  110.         if [[ -z "$DEP_FILE" ]] ; then
  111.             DEP_FAIL=1
  112.             DEP_FILE="Not found."
  113.             DEP_STATUS="FAILURE!"
  114.         else
  115.             DEP_STATUS="Success!"
  116.         fi
  117.         echo "Checking dependancy tool: $EACH ...  Status: $DEP_STATUS  : Path: $DEP_FILE"
  118.     done
  119.     echo ""
  120.     if [[ "$DEP_FAIL" == 1 ]] ; then
  121.         echo "ERROR: At least one dependancy check failed. You will need to fix this or this script will not work."
  122.         echo "Quitting."
  123.         echo ""
  124.         exit 1
  125.     else
  126.         echo "All dependancies found successfully."
  127.         echo ""
  128.     fi
  129.     #
  130.     # Verify that SteamCMD is installed where it should be.
  131.     echo "We will now verify that SteamCMD is installed where it should be."
  132.     echo ""
  133.     echo "VERIFICATION: Shall we continue?"
  134.     read -e -r -p "y/N: " -i "" REPLY
  135.     if [[ ! "$REPLY" == [yY] ]]; then
  136.         echo ""
  137.         echo "Quitting."
  138.         echo ""
  139.         exit 0
  140.     fi
  141.     echo ""
  142.     if [[ -x "$STEAMCMD_BIN" ]] ; then
  143.         echo "SteamCMD found successfully!"
  144.     else
  145.         echo "ERROR: SteamCMD not found. Install SteamCMD or fix the path to the executable/script."
  146.         echo "Qutting."
  147.         echo ""
  148.         exit 1
  149.     fi
  150.     echo ""
  151.     #
  152.     # APPDIR check and creation.
  153.     echo "Now we will check if the configured APPDIR exists, and create it if necessary."
  154.     echo "This is where the server installation directories will reside."
  155.     echo ""
  156.     # Test to see if APPDIR already exists.
  157.     if [[ -d "$APPDIR" ]] ; then
  158.         echo "NOTICE: APPDIR $APPDIR already seems to exist."
  159.         echo "VERIFICATION: Shall we continue anyway?"
  160.         read -e -r -p "y/N: " -i "" REPLY
  161.         if [[ ! "$REPLY" == [yY] ]]; then
  162.             echo ""
  163.             echo "Quitting."
  164.             echo ""
  165.             exit 0
  166.         fi
  167.     else
  168.         echo -n "Creating the APPDIR directory at: $APPDIR ..."
  169.         mkdir "$APPDIR" ; X_MKDIR_APPDIR=$?
  170.         if [[ "$X_MKDIR_APPDIR" == 0 ]] ; then
  171.             echo "Successful."
  172.             # Quietly set perms.
  173.             # chmod u=wrx,g=rx,o-wrx "$APPDIR"
  174.         else
  175.             echo "Failure."
  176.             echo ""
  177.             echo "The attempt to create the APPDIR failed. This is probably because you don't have filesystem permission to do so."
  178.             echo "This is not unexpected if you were trying to install into /srv."
  179.             echo ""
  180.             echo "We will try again with sudo..."
  181.             sudo -E mkdir "$APPDIR" ; X_SUDO_MKDIR_APPDIR=$?
  182.             if [[ "$X_SUDO_MKDIR_APPDIR" == 0 ]] ; then
  183.                 # Quietly set ownership and perms.
  184.                 sudo -E chown $RUNUSER:$RUNUSER "$APPDIR"
  185.                 sudo -E chmod u=wrx,g=rx,o-wrx "$APPDIR"
  186.                 echo "Success. We have created the APPDIR where new Starbound installations will reside."
  187.             else
  188.                 echo "Failure."
  189.                 echo ""
  190.                 echo "ERROR: We failed to create the APPDIR with sudo. Either change the APPDIR location, or manually create it."
  191.                 echo "Quitting."
  192.                 echo ""
  193.                 exit 1
  194.             fi
  195.         fi
  196.     fi
  197.     echo ""
  198.     echo "The next step is to install a Starbound master installation."
  199.     echo "This is the real installation from which all other installations will be linked to."
  200.     echo "Note that if an installation already exists in this location, we will try to update it."
  201.     echo ""
  202.     echo "VERIFICATION: Shall we continue?"
  203.     read -e -r -p "y/N: " -i "" REPLY
  204.     if [[ ! "$REPLY" == [yY] ]]; then
  205.         echo ""
  206.         echo "Quitting."
  207.         echo ""
  208.         exit 0
  209.     fi
  210.     if [[ -d "$APPDIR/$MASTER_INSTALLID" ]] ; then
  211.         echo ""
  212.         echo "NOTICE: A directory already exists at $APPDIR/$MASTER_INSTALLID."
  213.     else
  214.         # Try to create the master installation directory.
  215.         mkdir $APPDIR/$MASTER_INSTALLID ; X_MKDIR_MASTER_INSTALLID=$?
  216.         echo ""
  217.         if [[ "$X_MKDIR_MASTER_INSTALLID" == 0 ]] ; then
  218.             echo "New installation directory created successfully."
  219.         else
  220.             echo "ERROR: New master installation directory creation failed."
  221.             echo "Quitting."
  222.             echo ""
  223.             exit 1
  224.         fi
  225.     fi
  226.     f_update
  227.     echo "Bootstrap process completed!"
  228.     echo "You should now be able to install new Starbound linked servers. Use the \"install\" argument to do so."
  229.     echo ""
  230.     exit 0
  231. }
  232.  
  233. f_start() {
  234.     # Find out if server is already running, and error out if true.
  235.     f_getpid
  236.     if [[ -n "$SERVPID" ]] ; then
  237.         echo ""
  238.         echo "ERROR: Server already running?  PID: $SERVPID."
  239.         echo "Quitting."
  240.         echo ""
  241.         exit 1
  242.     fi
  243.     # Make sure we have a binary or link to run. This will prevent a bad installation from trying to start.
  244.     # NOTE: Due to the bug with starbound_server needing to be a real file, this isn't a good test.
  245.     if [[ ! -x "$BINDIR/$APPBIN" ]] ; then
  246.         echo ""
  247.         echo "ERROR: Server executable not found: $BINDIR/$APPBIN"
  248.         echo "Quitting."
  249.         echo ""
  250.         exit 1
  251.     fi
  252.     # Test for conflicting tmux session.
  253.     tmux has-session -t "$SERVNAME" 2> /dev/null
  254.     TMUXCONFLICT=$?
  255.     if [[ ! "$TMUXCONFLICT" -eq 1 ]] ; then
  256.         echo ""
  257.         echo "ERROR: A tmux session named \"$SERVNAME\" already exists, or tmux is broken."
  258.         echo "Quitting."
  259.         echo ""
  260.         exit 1
  261.     fi
  262.     # Check for an update lock.
  263.     f_lockcheck
  264.     #
  265.     # Continue if sane.
  266.     #
  267.     # If this is the first time a server is starting, we will automatically shut it down and warn the user.
  268.     if [[ ! -f "$SBCFGFILE" ]] ; then
  269.         NEWSERVER=1
  270.         echo ""
  271.         echo "WARNING: The default configuration file was not found."
  272.         echo "This is probably a new server being started for the first time."
  273.         echo "A default starbound.config file, universe, and other files will be automatically created."
  274.         echo "The server will automatically be shut down so that you may customize it's config file."
  275.         echo "Note that there may be errors encountered on shutdown; this is normal."
  276.     fi
  277.     #
  278.     # The server overwrites the log file, so rotate it on start if it is there.
  279.     if [[ -f "$APPDIR/$SERVNAME/starbound_server.log" ]] ; then
  280.         mv $APPDIR/$SERVNAME/starbound_server.log $APPDIR/$SERVNAME/starbound_server_$(date +%Y%m%d%H%M%S)-$$.log
  281.     fi
  282.     #
  283.     echo ""
  284.         echo "Starting $SERVNAME..."
  285.         cd "$APPDIR/$SERVNAME"
  286.         # tmux new-session -d -s "$SERVNAME" "$BINDIR/$APPBIN ; rm -f $PIDFILE"
  287.         tmux new-session -d -s "$SERVNAME" "$BINDIR/$APPBIN"
  288.         TMUXEXIT=$?
  289.     #
  290.     # Check the tmux exit code for errors.
  291.     if [[ $TMUXEXIT -ne 0 ]] ; then
  292.         echo "ERROR: tmux failed to run or experienced an error."
  293.         echo "TMUXEXIT was $TMUXEXIT."
  294.         echo "Server may not have started. Check status."
  295.     fi
  296.     # Need to wait for the PID to be obtained, but tmux returns immediately.
  297.     #
  298.     # Since the app itself can not yet write a PID file, we need to get it via tmux, but we must wait for the process to start.
  299.     # WARNING: Do not add any other commands to the tmux new-session command or this won't work correctly. Arguments are okay.
  300.     until [[ -n "$GETPID_TMUX" ]] ; do
  301.         GETPID_TMUX=$(tmux list-panes -t "$SERVNAME" -F '#{pane_pid}')
  302.         sleep 1
  303.     done
  304.     #
  305.     echo "$GETPID_TMUX" >> $PIDFILE || { echo "" ; echo "ERROR: Unable to write PIDFILE: $PIDFILE !" ; f_stop ; exit 1 ; }
  306.     # Note that this waiting here does not currently make sense due to getting the PID from tmux.
  307.     # When the application has a -pidfile option, this will be needed. Keep this.
  308.     #
  309.     echo -n "Waiting for server to start..."
  310.     STARTWAITCOUNT=0
  311.     until [[ -n "$SERVPID" ]] ; do
  312.         f_getpid
  313.         STARTWAITCOUNT=$(( $STARTWAITCOUNT + 1))
  314.         if [[ "$STARTWAITCOUNT" -gt 9 ]] ; then
  315.             echo ""
  316.             echo "ERROR: Done waiting. Startup may have failed. Check status."
  317.             echo ""
  318.             break
  319.         fi
  320.         sleep 1
  321.         echo -n "."
  322.     done
  323.     echo ""
  324.     # Now that the PIDFILE should be readable, get the PID.
  325.     f_getpid
  326.     #
  327.     if [[ -n "$SERVPID" ]] ; then
  328.         echo "Server started at PID $SERVPID."
  329.     else
  330.         echo "ERROR: Unable to get the PID."
  331.     fi
  332.     #
  333.     # Renice the process to make sure it runs as smooth as possible.
  334.     # This requires pam_limits configation via "/etc/security/limits.conf".
  335.     # Test if this is configured properly, and try to use it if so.
  336.     if [[ -n "$SERVPID" ]] && (egrep "$RUNUSER.*nice" /etc/security/limits.conf &> /dev/null) ; then
  337.         echo "Renicing process..."
  338.         bash -c "renice -10 $SERVPID 1> /dev/null"
  339.         RENICEEXIT=$?
  340.         if [[ ! "$RENICEEXIT" = 0 ]] ; then
  341.             echo "Raising the priority of the game server process failed."
  342.             echo "This might be due to pam_limits not being configured corrently."
  343.             echo ""
  344.         fi
  345.     fi
  346.     echo ""
  347.     #
  348.     # If this is a new server, we will want to automatically shut it down, assuming it doesn't shut itself down first, which is likely.
  349.     if [[ "$NEWSERVER" == 1 ]] ; then
  350.         STOPWAITFOR=30
  351.         echo -n "Waiting for new server to stop (max $STOPWAITFOR seconds)..."
  352.         STOPWAITCOUNT=0
  353.         # while [[ -f "$PIDFILE" ]] ; do
  354.         while [[ -n "$(ps --no-headers -p $SERVPID -o pid)" ]] ; do
  355.             STOPWAITCOUNT=$(( $STOPWAITCOUNT + 1))
  356.             if [[ "$STOPWAITCOUNT" -gt "$STOPWAITFOR" ]] ; then
  357.                 echo "Forcefully stopping server."
  358.                 f_stop
  359.                 break
  360.             fi
  361.             sleep 1
  362.             echo -n "."
  363.         done
  364.         if [[ -f "$PIDFILE" ]] ; then
  365.             rm -f "$PIDFILE"
  366.         fi
  367.         echo ""
  368.         echo "New server shutdown completed. After you have configured it, you may start it normally."
  369.         echo ""
  370.     else
  371.         echo "Server startup completed."
  372.         echo ""
  373.     fi
  374. }
  375.  
  376. f_stop() {
  377.     STOPFAIL=0
  378.     f_getpid
  379.     echo ""
  380.     echo "Stopping $SERVNAME ..."
  381.     if [[ -n "$SERVPID" ]] ; then
  382.         kill -SIGINT $SERVPID
  383.         # Now verify that the process is actually gone via the PID.
  384.         STOPWAITFOR=30
  385.         if [[ -n "$(ps --no-headers -p $SERVPID -o pid)" ]] ; then
  386.             echo -n "Waiting for server to stop..."
  387.             STOPWAITCOUNT=0
  388.             while [[ -n "$(ps --no-headers -p $SERVPID -o pid)" ]] ; do
  389.                 STOPWAITCOUNT=$(( $STOPWAITCOUNT + 1))
  390.                 if [[ "$STOPWAITCOUNT" -gt "$STOPWAITFOR" ]] ; then
  391.                     echo ""
  392.                     echo "Giving up waiting after $STOPWAITFOR seconds. Stop may have failed."
  393.                     echo ""
  394.                     echo "Here's the process info:"
  395.                     ps uw -p $SERVPID
  396.                     echo ""
  397.                     echo "Sending kill SIGQUIT to the process..."
  398.                     kill -SIGQUIT $SERVPID
  399.                     echo "Done."
  400.                     STOPFAIL=1
  401.                     break
  402.                 fi
  403.                 sleep 1
  404.                 echo -n "."
  405.             done
  406.             echo ""
  407.         fi
  408.         # Delete the PID file if necessary.
  409.         if [[ -f "$PIDFILE" ]] ; then
  410.             rm -f "$PIDFILE"
  411.         fi
  412.     else
  413.         STOPFAIL=1
  414.         echo ""
  415.         echo "PID not found. Is the server not running?"
  416.         echo ""
  417.     fi
  418.     # Kill the tmux session too, if it doesn't exit naturally.
  419.     #
  420.     # FIXME: Do not attempt to redirect stderr here. See tmux bug 3199205. Redirect tmux is broke.
  421.     # verify with; "tmux info > outfile", which will probably hang your terminal.
  422.     # As a result, you will see "session not found:" when stopping servers. Can't fix this.
  423.     #
  424.     #if tmux has-session -t $SERVNAME 2> /dev/null ; then
  425.     #
  426.     # echo "Ignore any \"session not found:\" messages here..."
  427.     if tmux has-session -t "$SERVNAME" 2> /dev/null ; then
  428.         echo -n "Waiting for tmux session to die..."
  429.         TMUXDIEWAITCOUNT=0
  430.         while tmux has-session -t "$SERVNAME" 2> /dev/null ; do
  431.         # while tmux has-session -t "$SERVNAME" ; do
  432.             TMUXDIEWAITCOUNT=$(( $TMUXDIEWAITCOUNT + 1))
  433.             if [[ "$TMUXDIEWAITCOUNT" -gt 3 ]] ; then
  434.                 echo ""
  435.                 echo "Giving up waiting for tmux session to die."
  436.                 echo ""
  437.                 echo "Killing the tmux session, which should kill everything..."
  438.                 tmux kill-session -t "$SERVNAME"
  439.                 echo "Done."
  440.                 STOPFAIL=1
  441.                 break
  442.             fi
  443.             sleep 1
  444.             echo -n "."
  445.         done
  446.         echo ""
  447.     fi
  448.     if [[ "$STOPFAIL" == 0 ]] ; then
  449.         echo "Game server $SERVNAME was stopped successfully."
  450.     else
  451.         echo "Game server $SERVNAME stop request encountered errors."
  452.     fi
  453.     echo ""
  454. }
  455.  
  456. f_status() {
  457.     echo ""
  458.     f_getpid
  459.     if [[ -n "$SERVPID" ]] ; then
  460.         echo "Showing status for $SERVNAME..."
  461.         echo ""
  462.         echo "tmux session:"
  463.         tmux list-sessions | egrep "^ *${SERVNAME}:"
  464.         echo ""
  465.         echo "Game server PID: $SERVPID"
  466.         echo ""
  467.         PROCINFO_ARGS=$(ps --no-headers -p $SERVPID -o args)
  468.         echo "Process command arguments:"
  469.         echo "$PROCINFO_ARGS"
  470.         echo ""
  471.         echo "Various ps stats:"
  472.         PROCINFO_PCPU=$(ps --no-headers -p $SERVPID -o pcpu)
  473.         echo "CPU usage percent per-core is:  $PROCINFO_PCPU%"
  474.         PROCINFO_PPRIO=$(ps --no-headers -p $SERVPID -o pri | sed -e "s/ \{1,\}//g")
  475.         echo "Process priority (normal=19, higher=better):  $PROCINFO_PPRIO"
  476.         PROCINFO_PSR=$(ps --no-headers -p $SERVPID -o psr | sed -e "s/ \{1,\}//g")
  477.         echo "Running on processor core:  $PROCINFO_PSR"
  478.         PROCINFO_EUSER=$(ps --no-headers -p $SERVPID -o euser)
  479.         echo "Running as effective user:  $PROCINFO_EUSER"
  480.         PROCINFO_RSS=$(ps --no-headers -p $SERVPID -o rss)
  481.         echo "RSS/Real memory usage:  $PROCINFO_RSS KB"
  482.         PROCINFO_VSZ=$(ps --no-headers -p $SERVPID -o vsz)
  483.         echo "VSZ/Virtual memory usage:  $PROCINFO_VSZ KB"
  484.         PROCINFO_LSTART=$(ps --no-headers -p $SERVPID -o lstart)
  485.         echo "Process started at:  $PROCINFO_LSTART"
  486.         PROCINFO_ETIME=$(ps --no-headers -p $SERVPID -o etime | sed -e "s/ \{1,\}//g")
  487.         echo "Process started elapsed-time ago:  $PROCINFO_ETIME"
  488.         PROCINFO_CPUTIME=$(ps --no-headers -p $SERVPID -o cputime)
  489.         echo "Process CPU in-use time:  $PROCINFO_CPUTIME"
  490.         echo ""
  491.         echo "lsof says the following network sockets are in use by PID $SERVPID:"
  492.         lsof -i -n -a -p $SERVPID
  493.         echo ""
  494.         #
  495.         echo "Done."
  496.     else
  497.         echo "ERROR: PID not found. Not running?"
  498.     fi
  499.     echo ""
  500. }
  501.  
  502. f_list() {
  503.     # List all valid server installations and show some basic info about each.
  504.     f_listinstalls
  505.     # $LIST_INSTALLS
  506.     echo ""
  507.     if [[ -z "$LIST_INSTALLS" ]] ; then
  508.         echo "No valid server installations to list."
  509.     else
  510.         echo "Listing all valid server installations..."
  511.         for EACH in $LIST_INSTALLS ; do
  512.             SERVNAME="$EACH"
  513.             # Discover if the server is running.
  514.             f_getpid
  515.             echo "Server: $EACH  Status: $SERVSTATUS"
  516.         done
  517.     fi
  518.     echo ""
  519. }
  520.  
  521. f_lockcheck() {
  522.     # Check if a lock has been placed on the master installation to prevent a train wreck, quit if found.
  523.     if [[ -r "$LOCKFILE" ]] ; then
  524.         echo "ERROR: lockfile active. Is an update already in progress?"
  525.         echo "Lockfile: $LOCKFILE"
  526.         echo "Quitting."
  527.         echo ""
  528.         exit 1
  529.     fi
  530. }
  531.  
  532. f_update() {
  533.     # Update with SteamCMD.
  534.     #
  535.     # Make sure SteamCMD is properly configured.
  536.     if [[ -z "$STEAMCMD_DIR" ]] || [[ ! -d "$STEAMCMD_DIR" ]] ; then
  537.         echo ""
  538.         echo "ERROR: The STEAMCMD_DIR is invalid or unset."
  539.         echo "Quitting."
  540.         echo "" ; exit 1
  541.     elif [[ -z "$STEAMCMD_BIN" ]] || [[ ! -x "$STEAMCMD_BIN" ]] ; then
  542.         echo ""
  543.         echo "ERROR: The STEAMCMD_BIN is invalid, unset, or not executable."
  544.         echo "Qutting."
  545.         echo "" ; exit 1
  546.     elif [[ -z "$STEAMCMD_SERVER_APPID" ]] ; then
  547.         echo ""
  548.         echo "ERROR: STEAMCMD_SERVER_APPID is blank or invalid."
  549.         echo "Quitting."
  550.         echo "" ; exit 1
  551.     elif [[ -z "$STEAMCMD_USER" ]] || [[ -z "$STEAMCMD_PASSWD" ]] ; then
  552.         echo ""
  553.         echo "ERROR: The STEAMCMD_USER and or STEAMCMD_PASSWORD is invalid or unset."
  554.         echo "Quitting."
  555.         echo "" ; exit 1
  556.     fi
  557.     #
  558.     # Unlock directory for writing. Normally it should be read-only.
  559.     f_unlockmaster
  560.     # Lockfile check and set.
  561.     f_lockcheck
  562.     echo $$ >> $LOCKFILE || { echo "ERROR: Unable to lock server. Is an update already in progress?" ; echo "" ; exit 1 ; }
  563.     UPDATING=1
  564.     f_listinstalls
  565.     #
  566.     echo ""
  567.     echo "Updating with SteamCMD..."
  568.     echo ""
  569.     declare -i UPDATECOUNTER="0"
  570.     if [[ "$VERIFYUPDATE" == "1" ]] ; then
  571.         echo "Updating with -verify_all/Validate."
  572.         UPDATEARG="+app_update $STEAMCMD_SERVER_APPID validate"
  573.     else
  574.         UPDATEARG="+app_update $STEAMCMD_SERVER_APPID"
  575.     fi
  576.     #
  577.     echo "Any linked server installations will automatically be stopped..."
  578.     if [[ -z "$LIST_INSTALLS" ]] ; then
  579.         echo ""
  580.         echo "No linked server installations found."
  581.         echo ""
  582.     else
  583.         for EACH in $LIST_INSTALLS ; do
  584.             SERVNAME=$EACH
  585.             f_getpid
  586.             # echo "DEBUG: SERVNAME: $SERVNAME EACH: $EACH SERVPID: $SERVPID"
  587.             if [[ -n "$SERVPID" ]] ; then
  588.                 echo "Server $EACH needs to be stopped."
  589.                 f_stop
  590.             else
  591.                 echo "Server $EACH is not running."
  592.             fi
  593.         done
  594.         echo "All servers stopped."
  595.         echo ""
  596.     fi
  597.     #
  598.     # cd to the SteamCMD dir so steamcmd doesn't litter crap tmp dirs wherever $PWD happens to be, which it does often.
  599.     cd $STEAMCMD_DIR
  600.     while true ; do
  601.         $NICECMD $STEAMCMD_BIN +@ShutdownOnFailedCommand 1 +login "$STEAMCMD_USER" "$STEAMCMD_PASSWD" +force_install_dir $APPDIR/$MASTER_INSTALLID/ $UPDATEARG +exit
  602.         UPDATEEXIT=$?
  603.         UPDATECOUNTER=$(( $UPDATECOUNTER + 1)) # Increment the counter
  604.         echo ""
  605.         echo "Updater exit code was $UPDATEEXIT"
  606.         if [[ "$UPDATEEXIT" = 0 ]] ; then
  607.             echo ""
  608.             echo "Update completed."
  609.             break
  610.         else
  611.             echo ""
  612.             echo "Update did not succeed."
  613.             if [[ "$UPDATECOUNTER" -lt "3" ]] ; then
  614.                 echo "Try $UPDATECOUNTER failed, will try again..."
  615.                 sleep 1
  616.                 continue
  617.             fi
  618.             if [[ "$UPDATECOUNTER" -eq "3" ]] ; then
  619.                 echo "ERROR: Tried $UPDATECOUNTER times already. Will not try again. Quitting."
  620.                 break
  621.             fi
  622.         fi
  623.     done
  624.     #
  625.     # Remove lockfile.
  626.     rm -f $LOCKFILE
  627.     #
  628.     # Lock down the master installation to make it read-only.
  629.     f_lockdownmaster
  630.     #
  631.     # We must relink all linked server installations.
  632.     echo "Relinking all linked server installations..."
  633.     if [[ -z "$LIST_INSTALLS" ]] ; then
  634.         echo ""
  635.         echo "No linked server installations found."
  636.         echo ""
  637.     else
  638.         for EACH in $LIST_INSTALLS ; do
  639.             SERVNAME=$EACH
  640.             f_relink
  641.         done
  642.         echo "All server installations relinked."
  643.         echo ""
  644.     fi
  645.     echo ""
  646.     echo "Update completed."
  647.     echo ""
  648. }
  649.  
  650. f_relink() {
  651.     # Refresh the links on a linked server installation to it's master installation.
  652.     # This is basically the upgrade procedure for a linked installation.
  653.     #
  654.     # Test that a master exists. This is unlikely to be a problem, but it is possible.
  655.     if [[ -z "$MASTER_INSTALLID" ]] ; then
  656.         echo ""
  657.         echo "ERROR: No master installation specified."
  658.         echo "Quitting."
  659.         echo ""
  660.         exit 1
  661.     fi
  662.     # Verify that the master installation directory exists, and err out if there is a problem.
  663.     if [[ ! -d "$APPDIR/$MASTER_INSTALLID" ]] ; then
  664.         echo ""
  665.         echo "ERROR: No Master installation directory found at: $APPDIR/$MASTER_INSTALLID"
  666.         echo "Quitting."
  667.         exit 1
  668.     fi
  669.     echo ""
  670.     echo "Relinking $SERVNAME ..."
  671.     $NICECMD lns -q -r "$APPDIR/$MASTER_INSTALLID/"* "$APPDIR/$SERVNAME" ; X_LNS_RELINK=$?
  672.     if [[ ! "$X_LNS_RELINK" == 0 ]] ; then
  673.         echo ""
  674.         echo "ERROR: The linking process failed."
  675.         echo "Quitting."
  676.         exit 1
  677.     fi
  678.     # Remove old dangling symlinks.
  679.     echo "Looking for old dangling symlinks and removing them..."
  680.     $NICECMD symlinks -d -r "$APPDIR/$SERVNAME"
  681.     # NOTE: We don't delete old empty directories, because we have no way to identify them. Could use "find -type d -empty" though.
  682.     #
  683.     # Delete the SteamCMD temp crap directories from linked installs. These are the 40-character 0-9a-f directories.
  684.     for EACH in $(find $APPDIR/$MASTER_INSTALLID -maxdepth 1 -mindepth 1 -type d) ; do
  685.         EACHN=$(basename $EACH | egrep "^[0-9a-f]{40}$")
  686.         if [[ -n "$EACHN" ]] ; then
  687.             # echo "DEBUG: would delete SteamCMD tempdir: $EACHN"
  688.             # rm -rf "$APPDIR/$SERVNAME/$EACHN"
  689.             # The following commands are much safer than rm -rf.
  690.             $NICECMD find "$APPDIR/$SERVNAME/$EACHN" -type l -lname "*../$MASTER_INSTALLID/*" -exec rm -f '{}' +
  691.             $NICECMD find "$APPDIR/$SERVNAME/$EACHN" -type d -empty -delete
  692.         fi
  693.     done
  694.     # Due to bugs in the starbound_server binary being incompatible with symlinks, we need to make a real copy of it.
  695.     # starbound_server will not work as a symlink because it will try and set it's $PWD to the master install instead of the linked install.
  696.     # Hopefully this bug will be fixed in the future and we won't have to do this.
  697.     $NICECMD rm -f "$APPDIR/$SERVNAME/linux32/$APPBIN"
  698.     $NICECMD rm -f "$APPDIR/$SERVNAME/linux64/$APPBIN"
  699.     $NICECMD cp "$APPDIR/$MASTER_INSTALLID/linux32/$APPBIN" "$APPDIR/$SERVNAME/linux32/$APPBIN"
  700.     $NICECMD cp "$APPDIR/$MASTER_INSTALLID/linux64/$APPBIN" "$APPDIR/$SERVNAME/linux64/$APPBIN"
  701.     #
  702.     echo ""
  703.     echo "Relinking complete."
  704.     echo ""
  705. }
  706.  
  707. f_delink() {
  708.     # Delete the links from a linked installation to it's master installation.
  709.     # NOTE: This should not touch other links which are not related to the master.
  710.     #
  711.     echo ""
  712.     echo "This will delete all symbolic links in the \"$SERVNAME\" installation directory which refer to the Master install."
  713.     echo "This will NOT delete symbolic links which refer to other locations."
  714.     echo ""
  715.     echo "Are you sure you want to do this?"
  716.     echo ""
  717.     echo "VERIFICATION: Delink $SERVNAME ?"
  718.     read -e -r -p "y/N: " -i "" REPLY
  719.     if [[ ! "$REPLY" == [yY] ]]; then
  720.         echo ""
  721.         echo "Quitting."
  722.         echo ""
  723.         exit 0
  724.     fi
  725.     echo ""
  726.     #
  727.     # Due to the starbound_server needing to be a real file bug, we should go ahead and delete those files here.
  728.     # Hopefully we can stop doing this in the future.
  729.     $NICECMD rm -f "$APPDIR/$SERVNAME/linux64/$APPBIN"
  730.     $NICECMD rm -f "$APPDIR/$SERVNAME/linux32/$APPBIN"
  731.     #
  732.     # NOTE: This is not completely safe. We are depending upon the -lname pattern matching, but it's close enough.
  733.     $NICECMD find "$APPDIR/$SERVNAME" -type l -lname "*../$MASTER_INSTALLID/*" -exec rm -f '{}' +
  734.     echo "Delinking completed with exit code $?."
  735.     echo ""
  736.     # Also offer to delete worthless empty directories that lns created during the linking process.
  737.     echo "Would you also like to delete all empty directories in the $SERVNAME installation directory?"
  738.     echo "This includes ALL directories which are empty of anything other than additionally nested empty directories."
  739.     echo ""
  740.     echo "VERIFICATION: Delete empty directories in \"$SERVNAME\"?"
  741.     read -e -r -p "y/N: " -i "" REPLY
  742.     if [[ ! "$REPLY" == [yY] ]]; then
  743.         echo ""
  744.         echo "Quitting."
  745.         echo ""
  746.         exit 0
  747.     else
  748.         find "$APPDIR/$SERVNAME" -type d -empty -delete
  749.         echo ""
  750.         echo "Done deleting empty directories."
  751.         echo ""
  752.     fi
  753. }
  754.  
  755. f_install() {
  756.     # Create a new linked server installation. For the master install, see f_update.
  757.     echo ""
  758.     echo "This process will install a new Starbound server installation."
  759.     echo ""
  760.     echo "Choose a unique name for this installation."
  761.     echo "Valid characters are a-z, A-Z, and 0-9. No other characters allowed."
  762.     if [[ -n "$INSTALL_PREFIX" ]] ; then
  763.         echo "NOTE: The installation prefix \"$INSTALL_PREFIX\" will automatically be prepended to the installation name. Do not include it here."
  764.     fi
  765.     echo ""
  766.     while read -e -r -p "Name: " -i "$IN_SERVNAME" SERVNAME_NEW ; do
  767.         # Validate the input.
  768.         if [[ -z "$SERVNAME_NEW" ]] || (echo "$SERVNAME_NEW" | egrep "[[:cntrl:]]|[[:punct:]]|[[:space:]]" &> /dev/null ) ; then
  769.             echo ""
  770.             echo "Invalid input detected. Try again."
  771.         else
  772.             # Prepend the installation prefix.
  773.             SERVNAME_NEW=${INSTALL_PREFIX}${SERVNAME_NEW}
  774.             echo ""
  775.             echo "Please confirm: New installation name will be \"${SERVNAME_NEW}\" ?"
  776.             # echo -n "y/N:"
  777.             read -e -r -p "y/N: " -i "" SERVNAME_NEW_CONFIRM
  778.             if [[ "$SERVNAME_NEW_CONFIRM" == [yY] ]]; then
  779.                 break
  780.             else
  781.                 echo ""
  782.                 echo "Okay then, we will try again. What name do you want?"
  783.             fi
  784.         fi
  785.     done
  786.     SERVNAME=$SERVNAME_NEW
  787.     # Verify that such an installation does not already exist.
  788.     if [[ -d "$APPDIR/$SERVNAME" ]] ; then
  789.         echo ""
  790.         echo "ERROR: A directory already exists at \"$APPDIR/$SERVNAME\"."
  791.         echo "Quitting."
  792.         echo ""
  793.         exit 1
  794.     fi
  795.     mkdir $APPDIR/$SERVNAME_NEW ; X_MKDIR_INSTALLID_NEW=$?
  796.     echo ""
  797.     if [[ "$X_MKDIR_INSTALLID_NEW" == 0 ]] ; then
  798.         echo "New installation directory created successfully."
  799.     else
  800.         echo "ERROR: New installation directory creation failed."
  801.         echo "Quitting."
  802.         exit 1
  803.     fi
  804.     # Now that we have our installation directory, link it up.
  805.     f_relink
  806.     echo "New server installation created. Be sure to configure it before attempting to start."
  807.     echo ""
  808. }
  809.  
  810. f_lockdownmaster() {
  811.     # Lock down the master installation from writing. This will prevent accidents.
  812.     echo -n "Locking down the master installation... "
  813.     $NICECMD find $APPDIR/$MASTER_INSTALLID -type f -exec chmod ugo-x '{}' +
  814.     $NICECMD find $APPDIR/$MASTER_INSTALLID/linux[63][42] -type f -exec chmod ugo+x '{}' +
  815.     $NICECMD find $APPDIR/$MASTER_INSTALLID -type f -exec chmod ugo+r '{}' +
  816.     $NICECMD find $APPDIR/$MASTER_INSTALLID -type d -exec chmod ugo+rx '{}' +
  817.     $NICECMD find $APPDIR/$MASTER_INSTALLID -type f -exec chmod ugo-w '{}' +
  818.     $NICECMD find $APPDIR/$MASTER_INSTALLID -type d -exec chmod ugo-w '{}' +
  819.     echo "Done."
  820. }
  821.  
  822. f_unlockmaster() {
  823.     # Unlock the master installation for writing. The only time this should be needed is for manual work or updating.
  824.     echo -n "Unlocking the master installation ... "
  825.     $NICECMD find $APPDIR/$MASTER_INSTALLID -type d -exec chmod ug+w '{}' +
  826.     $NICECMD find $APPDIR/$MASTER_INSTALLID -type f -exec chmod ug+w '{}' +
  827.     echo "Done."
  828. }
  829.  
  830. f_listinstalls() {
  831.     # Get a list of all linked installations. This excludes the master installation. Store in LIST_INSTALLS.
  832.     # We will also omit any directory with a "." in it's name.
  833.     for EACH in $(find $APPDIR -mindepth 1 -maxdepth 1 -type d | egrep -v "$MASTER_INSTALLID|.*\..*") ; do
  834.         EACHN=$(basename $EACH)
  835.         if [[ -z "$LIST_INSTALLS" ]] ; then
  836.             LIST_INSTALLS="$EACHN"
  837.         else
  838.             LIST_INSTALLS="$LIST_INSTALLS $EACHN"
  839.         fi
  840.     done
  841. }
  842.  
  843. f_console() {
  844.     # Attach to the tmux session for a given steam server.
  845.     # FIXME: Could use some test for the pidfile, warning if not found, etc.
  846.     echo ""
  847.     echo "Attaching to tmux session $SERVNAME..."
  848.     echo ""
  849.     tmux attach-session -t "$SERVNAME"
  850.     echo "Session detached or closed."
  851.     echo ""
  852.     exit 0
  853. }
  854.  
  855. f_mailnotify() {
  856.     # Mail notifications.
  857.     # Only send mail if MAILNOTIFY is set corretly.
  858.     if (echo "$MAILNOTIFY" | egrep -i "yes|true|1" &> /dev/null) ; then
  859.         $MAILER -s "STARBINDER: $SERVNAME $IN_ACTION" $MAILTO <<-ENDMESSAGE
  860.            
  861.             Date: $(date)
  862.             Server: $SERVNAME
  863.             Action: $IN_ACTION
  864.  
  865.         ENDMESSAGE
  866.     fi
  867. }
  868.  
  869. f_commandhelper() {
  870.     # Print this if input is nonsense.
  871.     echo ""
  872.     echo "I was expecting something like:"
  873.     echo "  $(basename $0) ($AVAIL_ACTIONS1)"
  874.     echo "OR"
  875.     echo "  $(basename $0) ($AVAIL_ACTIONS2) myserver"
  876.     echo ""
  877.     echo "For example:"
  878.     echo "  $(basename $0) start myserver"
  879.     echo ""
  880.     echo "Quitting."
  881.     echo ""
  882.     exit 1
  883. }
  884.  
  885.  
  886.  
  887. #--
  888. # Verify sanity before we start doing anything.
  889.  
  890. trap f_cleanuptrap SIGHUP SIGINT SIGQUIT SIGABRT
  891.  
  892. # Validate arguments.
  893. if [[ "$#" -eq 1 ]] ; then
  894.     # Validate single arguments.
  895.     if [[ "$IN_ACTION" != bootstrap ]] ; then
  896.         # For anything other than intial bootstrapping, the APPDIR must exist.
  897.         if [[ ! -d "$APPDIR" ]] ; then
  898.             echo ""
  899.             echo "ERROR: APPDIR \"$APPDIR\" not found!"
  900.             echo ""
  901.             echo "If you want to perform setup for the first time, use the \"bootstrap\" argument."
  902.             echo "Be sure you have read the ${MYNAME}_README.txt file first!"
  903.             echo ""
  904.             f_commandhelper
  905.         fi
  906.     fi
  907.     if ! (echo "$IN_ACTION" | egrep "$AVAIL_ACTIONS1" &> /dev/null) ; then
  908.         echo ""
  909.         echo "Action argument \"$IN_ACTION\" is not valid."
  910.         f_commandhelper
  911.     fi
  912. elif [[ "$#" -eq 2 ]] ; then
  913.     # Validate dual arguments.
  914.     if ! (echo "$IN_ACTION" | egrep "$AVAIL_ACTIONS2" &> /dev/null) ; then
  915.         echo ""
  916.         echo "Action argument \"$IN_ACTION\" is not valid."
  917.         f_commandhelper
  918.     fi
  919.     # Validate $SERVNAME, unless we are installing as new.
  920.     if [[ "$IN_ACTION" != install ]] ; then
  921.         if [[ ! -d "$APPDIR/$SERVNAME" ]] ; then
  922.             echo ""
  923.             echo "Installation argument \"$SERVNAME\" not found."
  924.             f_commandhelper
  925.         fi
  926.     fi
  927. elif [[ "$#" -gt 2 ]] ; then
  928.     # More than two arguments is an error.
  929.     echo ""
  930.     echo "Too many arguments."
  931.     f_commandhelper
  932. fi
  933.  
  934. # If we are not updating, immediately unset STEAMCMD_USER and STEAMCMD_PASSWD for security reasons.
  935. if ( echo "$IN_ACTION" | egrep -v "^update$|^update-validate$" &> /dev/null ) ;then
  936.     # echo "DEBUG: Unsetting auth info."
  937.     unset STEAMCMD_USER STEAMCMD_PASSWD
  938. fi
  939.  
  940. case "$IN_ACTION" in
  941.     'start')
  942.         f_mailnotify
  943.         f_start
  944.     ;;
  945.     'stop')
  946.         f_mailnotify
  947.         f_stop
  948.     ;;
  949.     'restart')
  950.         f_mailnotify
  951.         f_stop
  952.         sleep 1
  953.         f_start
  954.     ;;
  955.     'list')
  956.         f_list
  957.     ;;
  958.     'status')
  959.         f_status
  960.     ;;
  961.     'update')
  962.         f_mailnotify
  963.         f_update
  964.     ;;
  965.     'update-validate')
  966.         VERIFYUPDATE=1
  967.         f_mailnotify
  968.         f_update
  969.     ;;
  970.     'console')
  971.         f_console
  972.     ;;
  973.     'bootstrap')
  974.         f_bootstrap
  975.     ;;
  976.     'install')
  977.         f_install
  978.     ;;
  979.     'relink')
  980.         f_relink
  981.     ;;
  982.     'delink')
  983.         f_delink
  984.     ;;
  985.     'lockdown-master')
  986.         f_lockdownmaster
  987.     ;;
  988.     'unlock-master')
  989.         f_unlockmaster
  990.     ;;
  991.     *)
  992.         echo ""
  993.         echo "Missing arguments."
  994.         f_commandhelper
  995. esac
  996.  
  997. exit 0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement