Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I've got a shell script, which is essentially a one liner with some logging, which I'm trying to run this from an init script. I'm using the daemon function inside of /etc/init.d/functions to run it, as Redhat does not appear to have start-stop-daemon available. When I call the init script (/etc/init.d/script start) it stays in the foreground, rather than completing and leaving the process running. What's the proper way for me to get this script daemonized?

Script to be run:

# conf file where variables are defined
. /etc/script.conf

echo "Starting..." | logger -i
echo "Monitoring $LOG_LOCATION." | logger -i
echo "Sending to $MONITOR_HOST:$MONITOR_PORT." | logger -i

tail -n 1 -F $LOG_LOCATION |
grep WARN --line-buffered  |
/usr/bin/nc -vv $MONITOR_HOST $MONITOR_PORT 2>&1 |
logger -i

init script:

#!/bin/bash


# Source Defaults
. /etc/default/script

# Source init functions
. /etc/init.d/functions

prog=/usr/local/bin/script.sh

[ -f /etc/script.conf ] || exit 1

RETVAL=0

start()
{
    # Quit if disabled
    if ! $ENABLED; then
            echo "Service Disabled in /etc/default/script"
            exit 1
    fi

    echo "Starting $prog"

    daemon $prog

    RETVAL=$?

    return $RETVAL
}

stop ()
{
    echo -n $"Stopping $prog: "
    killproc $prog

    RETVAL=$?

    return $RETVAL
}

reload()
{
    echo "Reload command is not implemented for this service."
    return $RETVAL
}

restart()
{
    stop
    start
}

condrestart()
{
    echo "Not Implemented."
}

# See how we were called.
case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    status)
        status $prog
        ;;
    restart)
        restart
        ;;
    reload)
        reload
        ;;
    condrestart)
        condrestart
        ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|reload}"
        RETVAL=1
esac

Last ~20 lines of execution with bash -vx:

+ case "$1" in
+ start
+ true
+ echo 'Starting /usr/local/bin/script.sh'
Starting /usr/local/bin/script.sh
+ daemon /usr/local/bin/script.sh
+ local gotbase= force=
+ local base= user= nice= bg= pid=
+ nicelevel=0
+ '[' /usr/local/bin/script.sh '!=' /usr/local/bin/script.sh ']'
+ '[' -z '' ']'
+ base=script.sh
+ '[' -f /var/run/script.sh.pid ']'
+ '[' -n '' -a -z '' ']'
+ ulimit -S -c 0
+ '[' -n '' ']'
+ '[' color = verbose -a -z '' ']'
+ '[' -z '' ']'
+ initlog -q -c /usr/local/bin/script.sh
share|improve this question
    
It seems useful to me that you run that script through bash -vx ... and post the last lines so that we can see what stays in the foreground. –  Hauke Laging Apr 18 '13 at 18:57
    
Don't bother getting the usage of this right and go with daemon, there's a RPM package, too. Btw, there're many log monitoring tools out there (start here). –  sr_ Apr 18 '13 at 19:47
    
Hauke, do you mean using a first line of #!/bin/bash -vx? I tried doing this, but it didn't produce the same output from the init script as it does if I run the shell script directly. –  bshacklett Apr 18 '13 at 21:30
    
@bshacklett you can examine any init script's (any shell script's actually) function by running it explicitly with bash -vx, ie. bash -vx /etc/init.d/script start. –  sr_ Apr 19 '13 at 7:43
    
It appears to be stopping at + initlog -q -c /usr/local/bin/script.sh –  bshacklett Apr 19 '13 at 13:11
show 4 more comments

2 Answers

I don't know Redhat but daemon $prog & looks strange to me. If there is already a function for daemonizing why should it be necessary (and useful) to put this function itself in the background? Thus try without the &.

share|improve this answer
    
It's not wrong. /etc/init.d/functions defines a daemon function that expects its argument to daemonize itself, it only takes care of things like changing the user, setting ulimits, checking (not creating!) a pidfile... The best usage of this daemon function is to replace it with libslack's daemon ;) –  sr_ Apr 18 '13 at 19:43
    
I'm sorry, the & was there at one point when I was troubleshooting. I did not mean to include it in this post. –  bshacklett Apr 18 '13 at 21:25
add comment
up vote 0 down vote accepted

I found a script at http://www.linuxforums.org/forum/programming-scripting/190279-daemon-etc-init-d-functions-does-not-return-launching-process.html#post897522 which I was able to modify to suit my needs. It manually tracks the PID and creates a PID file using pidof. I ended up having to modify this to use pgrep as pidof was unable to see the PID of my script. After that modification, it worked fine. *Note, pgrep seems to only work if the full script name is under 15 characters long

Here's what I ended up with:

#!/bin/bash
#
# 
#
# Start on runlevels 3, 4 and 5. Start late, kill early.
# chkconfig: 345 95 05
#
#
#!/bin/bash

# absolute path to executable binary
progpath='/usr/local/bin/script.sh'

# arguments to script
opts=''

# binary program name
prog=$(basename $progpath)

# pid file
pidfile="/var/run/${prog}.pid"

# make sure full path to executable binary is found
! [ -x $progpath ] && echo "$progpath: executable not found" && exit 1

eval_cmd() {
  local rc=$1
  if [ $rc -eq 0 ]; then
    echo '[  OK  ]'
  else
    echo '[FAILED]'
  fi
  return $rc
}

start() {
  # see if running
  local pids=$(pgrep $prog)

  if [ -n "$pids" ]; then
    echo "$prog (pid $pids) is already running"
    return 0
  fi
  printf "%-50s%s" "Starting $prog: " ''
  $progpath $opts &

  # save pid to file if you want
  echo $! > $pidfile

  # check again if running
  pgrep $prog >/dev/null 2>&1
  eval_cmd $?
}

stop() {
  # see if running
  local pids=$(pgrep $prog)

  if [ -z "$pids" ]; then
    echo "$prog not running"
    return 0
  fi
  printf "%-50s%s" "Stopping $prog: " ''
  rm -f $pidfile
  kill -9 $pids
  eval_cmd $?
}

status() {
  # see if running
  local pids=$(pgrep $prog)

  if [ -n "$pids" ]; then
    echo "$prog (pid $pids) is running"
  else
    echo "$prog is stopped"
  fi
}

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

exit $?
share|improve this answer
    
Accepting this as the answer since there's been no other input for a while. –  bshacklett Apr 22 '13 at 22:10
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.