4
votes

I have this proprietary program called lightid and I would like to run it as a daemon. The developer of lightid added a "-d" switch to the command line options to be able to run it as a daemon. Using sample-service-script, I created a proper start/stop bash script and installed it as a service in order to be able to control it using service lightid start service lightid stop service lightid status etc... and most importantly this way I can check its status using monit. The start function of the bash script (to be put in /etc/init.d/lightid) looks something like this

SCRIPT="/home/foo/lightid -d"
RUNAS=giulio
NAME=lightid
PIDFILE=/var/run/$NAME.pid
LOGFILE="/dev/null"
CMD="$SCRIPT &> \"$LOGFILE\" & echo \$!"
su -c "$CMD" $RUNAS > "$PIDFILE"

as you can see, the su command is supposed to return the pid of the daemon so that this can be written to $PIDFILE, and its status can be checked using PID=$(cat $PIDFILE) ps axf | grep ${PID} | grep -v grep and the daemon can be killed using kill -15 $(cat "$PIDFILE")

The issue is that the line above su -c "$CMD" $RUNAS > "$PIDFILE" writes to $PIDFILE a pid that is not the same of the process that is running in the background. For instance, it would return 9933 whereas the process running in the background would have pid=9935 . The actual pid is always the returned value +2. I asked the developer of lightid what its "-d" switch actually does and if this could be somehow the reason why the actual pid differs from the one returned by su. In fact, I suspect that the returned pid is the one of the parent process which terminates as soon as it "daemonizes" itself after the fork. He replied to me

"The reason I create the daemon the way I do is because that's what's documented in Michael Kerrisk's book The Linux Programming Interface. The reasons he gives are:

1.) By forking and terminating the parent the child becomes a child of the init process.

2.) The child needs to call setsid to start a new session and free itself from the controlling terminal.

3.) The second fork ensures the process is not a session leader and thus can't re-acquire the controlling terminal (System V requirement).

I've never come across a means of creating a daemon without forking so the problem of getting the processes PID the way you want to is, I'm afraid, not something I've dealt with before."

Is there any way I can get the correct pid? Should I just run lightid in non-daemon mode by appropriately redirecting stdin,stdout and stderr to /dev/null ?

1
That assignment to CMD seems full of opportunities for problems. What happes if you just run su -c $SCRIPT &> $LOGFILE & followed by echo $! > $PIDFILE on a separate line? Good luck.shellter

1 Answers

2
votes

Like you've correctly deduced, the problem is that your script daemonizes the lightid launcher which daemonizes the lightid service.

Since you're daemonizing the daemonizer instead of the actual service, you end up with the wrong pid.

You should ensure that there is only one daemonizer involved. If lightid supports writing a pidfile natively, just use its functionality.

If it doesn't, you should use a tool meant for daemonizing things, like daemon, and have it run a non-daemonizing lightid. These tools redirect fds, creates sessions, resets signal handlers and all the other things that a casual daemonizer script would forget.