start-stop-daemon starting multiple processes - linux

I am trying to use start-stop-daemon to start a process that runs in the background. To my knowledge, start-stop-daemon is supposed to prevent a second process from being started if one is already running. The script I am running is rather simple for now:
#!/bin/sh
while true; do
date > /home/pi/test/test.txt
sleep 10
done
I am starting the script using start-stop-daemon --start -v -b -m --pidfile /var/run/test.pid --exec /home/pi/test/test.sh
I am able to successfully stop the script using start-stop-daemon --stop -v --pidfile /var/run/test.pid
However, if I run the start command twice, it will start two processes, instead of just one that I was expecting. Does the start command check the pid file before starting the process, or is there something else that needs to be done for that to happen?

The man page of start-stop-daemon contains a special warning on the usage of the --exec option with scripts.
-x, --exec executable
Check for processes that are instances of this executable. The executable
argument should be an absolute pathname. Note: this might not work as
intended with interpreted scripts, as the executable will point to the
interpreter.
When you run a script, the process that is actually launched is the interpreter noted in the shebang line of the script. This confuses the start-stop-daemon utility.
BTW, you can use the -t option to debug that kind of issues with start-stop-daemon.

Related

start-stop-daemon with --background vs running using & option

What is the difference in running a process in background using start-stop-daemon with --background option and using with &?Which option is best and why?
If you use start-stop-daemon --background then start-stop-daemon will fork off a process to run in the background and then start-stop-daemon immediately exits. Among other things this means you can check the exit status of start-stop-daemon.
If you use start-stop-daemon & then the shell forks off a background process and runs start-stop-daemon in it. You won't be able to check its exit status as it won't actually exit (until the thing it runs exits).
In most cases start-stop-daemon --background is a better choice.
I prefer the & option for making a background job. However, on the occasions that I forget to include the &, I use the Ctrl-Z command to stop the job and then enter bg to move the stopped command into the background.
While I have not observed any difference in the approaches (with the exception that & can be used in a script). A colleague of mine was very pleased to find out about the Ctrl-Z option of suspending a job. He claimed that he had some tasks where that "worked better".
If you want to learn more about Ctrl-Z and bg, look for bash job control.

Not able to stop init script using start-stop-daemon

I want to use start-stop-daemon to stop the scripts it has started, but currently the scripts are not killed, and so I have resorted to hacking around it:
#!/bin/sh
case $1 in
start)
start-stop-daemon --start --background -c myapp --exec /home/myapp/dev-myapp.sh
;;
stop)
# couldn't get this to work - hacking around it
#start-stop-daemon --stop -c myapp --exec /home/myapp/dev-myapp.sh
# hack
killall dev-myapp.sh
sleep 3
killall -9 dev-myapp.sh
;;
restart)
$0 stop
$0 start
;;
*)
echo "No such command. "
echo "Usage: $0 start|stop|restart"
esac
exit 0
How can I get the script to kill the bash scripts it has started using start-stop-daemon?
edit: I assume the failure to stop the processes has to do with this section from the man page:
-x, --exec executable
Check for processes that are instances of this executable. The executable argument should be an absolute pathname. Note: this
might not work as intended with interpreted scripts, as the executable will point to the interpreter. Take into account processes
running from inside a chroot will also be matched, so other match restrictions might be needed.
So I might be forced to rely on name detection instead, but I don't know what the process name is ... Is this the whole absolute filename, the filename alone, or something else?
Regarding your comment, if you're willing to extend the shellscript you are running, you can use a pidfile. In practice, maybe you want to make it an option to your script, but as an example, this line would be sufficient:
echo $$ >/var/run/dev-myapp.sh.pid
Then, use these matching parameters for start-stop-daemon, if necessary replacing /bin/bash with whatever shell executes your script:
-p /var/run/dev-myapp.sh.pid -x /bin/bash
(To clarify: The process name of the script is that of the script interpreter, in your case, the shell)

Script not starting on boot with start-stop-daemon

My script (located in /etc/init.d) is creating a pid file ($PIDFILE), but there is no process running. My daemon script includes:
start-stop-daemon --start --quiet --pidfile $PIDFILE -m -b --startas $DAEMON --test > /dev/null || return 1
The script works fine when executing it manually.
You need to create startup links.
sudo update-rc.d SCRIPT_NAME defaults
then reboot. SCRIPT_NAME is the name of the script in /etc/init.d (Without the path)
Was able to get it working, but tried so many things, don't know exactly what fixed it (probably an error in script or config). However, learned a lot and wanted to share since I can't find much of the same in the internet abyss.
It seems Ubuntu (and many other distros based on Ubuntu, including Mint) has migrated to Upstart for job and service management. Upstart includes SysVinit (using /etc/init.d daemons) compatibility that still can use update-rc.d to manage daemons (so if you are familiar with that usage, you can keep on using it). The Upstart method is to use a single .conf file in the /etc/init folder. My SCRIPT.conf file is very simple (I'm using a python script):
start on filesystem or runlevel [2345]
stop on runlevel [016]
exec python /usr/share/python-support/SCRIPT/SCRIPT.py
This simple file completely replaces the standard script in /etc/init.d with the case statement to provide [start|stop|restart|reload] functions and the pointer to /usr/bin/SCRIPT. You can see that it includes runlevel control that would normally be found in the /etc/rc*.d files (thus eliminating several files).
I tried update-rc.d to create the necessary /etc/rc*.d/ files for my daemon. My daemon bash script is located in /etc/init.d and includes the start-stop-daemon command as in my original question. (That command also works fine from terminal.)
I had /etc/rc*.d/ files, the bash script in /etc/init.d and /etc/init/SCRIPT.conf file during boot and it seems that Upstart likely first looks for the .conf file for its direction because the SysVinit command service SCRIPT [start|stop|restart|reload] returns Unknown Instance, however you can find the process is running with ps -elf | grep SCRIPT_FILE.
One interesting thing to note is the forking of your daemon when using .conf. The script as written above only spawns one fork of the daemon. However, total independence of the original script is possible by using expect fork or expect daemon and respawn (see the Upstart Cookbook for reference). Using these will ensure that your daemon will never be killed (at least by using the kill command).
I continued to test both my daemon and the boot process by utilizing the sudo initctl reload-configuration command. This reloads the conf files where you can test your daemon by the sudo [start|stop|restart] SCRIPT command. The result of the start command is:
$ sudo start SCRIPT
SCRIPT start/running, process xxxx
$ sudo restart SCRIPT
SCRIPT start/running, process xxxx
$ sudo stop SCRIPT
SCRIPT stop/waiting
Also, there is a nice log in /var/log/upstart/SCRIPT.log that gives you useful information for your daemon during boot. Mine still has a very annoying bug that prevents root from displaying osd messages with notify-send from my daemon. My log file includes a gtk warning (I will open another question to solicit help).
Hope this helps others in developing their daemons.

What is start-stop-daemon in linux scripting?

What is start-stop-daemon and how should it be used?
I am trying to automate a particular program to run. Whenever the system starts, the program should run. For that I am writing script in /etc/init.d/ location.
It is a program to manage the start and stop of system level background processes (daemons). You use it by passing in parameters (such as the pid file to create/check) and command arguments for the process you want to launch.
Then, you do one of two things:
start-stop-daemon -S [other arguments] something
start something, if something wasn't already running. If it was running, do nothing.
start-stop-daemon -K [other arguments] something
stop something. If something wasn't running, do nothing.
The man page provides more information on the various arguments. Typically a template is provided in /etc/init.d/ which has other commands for the init process that controls the running of background processes.
What does it mean?
start-stop-daemon --start --background -m --oknodo
--pidfile ${PIDFILE} --exec ${DAEMON} -- ${TARGETDIR}
--background = launch as a background process
-m = make a PID file. This is used when your process doesn't create its own PID file, and is used with --background
--oknodo = return 0, not 1 if no actions are taken by the daemon
--pidfile ${PIDFILE} = check whether the PID file has been created or not
--exec = make sure the processes are instances of this executable (in your case, DAEMON)
Copy the /etc/init.d/skeleton file (to e.g. /etc/init.d/rajeevdaemon or another good name), which is a shell script with a lot of comments, and edit it to suit your needs. Then add appropriate symlinks from e.g. /etc/rc2.d/S98rajeevdaemon and /etc/rc2.d/K98rajeevdaemon to it.
Read more about runlevels.
And recent (or future) Linux distributions are using more and more systemd

Upstart: Error when using command substitution in post-start script stanza during startup sequence

I'm seeing an issue in upstart where using command substitution inside a post-start script stanza causes an error (syslog reports "terminated with status 1"), but only during the initial system startup.
I've tried using just about every startup event hook under the sun. local-filesystems and net-device-up worked without error about 1/100 tries, so it looks like a race condition. It works just fine on manual start/stop. The command substitutions I've seen trigger the error are a simple cat or date, and I've tried using both the $() way and the backtick way. I've also tried using sleep in pre-start to beat the race condition but that did nothing.
I'm running Ubuntu 11.10 on VMWare with a Win7 host. Spent too many hours troubleshooting this already... Anyone got any ideas?
Here is my .conf file for reference:
start on runlevel [2345]
stop on runlevel [016]
env NODE_ENV=production
env MYAPP_PIDFILE=/var/run/myapp.pid
respawn
exec start-stop-daemon --start --make-pidfile --pidfile $MYAPP_PIDFILE --chuid node-svc --exec /usr/local/n/versions/0.6.14/bin/node /opt/myapp/live/app.js >> /var/log/myapp/audit.node.log 2>&1
post-start script
MYAPP_PID=`cat $MYAPP_PIDFILE`
echo "[`date -u +%Y-%m-%dT%T.%3NZ`] + Started $UPSTART_JOB [$MYAPP_PID]: PROCESS=$PROCESS UPSTART_EVENTS=$UPSTART_EVENTS" >> /var/log/myapp/audit.upstart.log
end script
post-stop script
MYAPP_PID=`cat $MYAPP_PIDFILE`
echo "[`date -u +%Y-%m-%dT%T.%3NZ`] - Stopped $UPSTART_JOB [$MYAPP_PID]: PROCESS=$PROCESS UPSTART_STOP_EVENTS=$UPSTART_STOP_EVENTS EXIT_SIGNAL=$EXIT_SIGNAL EXIT_STATUS=$EXIT_STATUS" >> /var/log/myapp/audit.upstart.log
end script
The most likely scenario I can think of is that $MYAPP_PIDFILE has not been created yet.
Because you have not specified an 'expect' stanza, the post-start is run as soon as the main process has forked and execed. So, as you suspected, there is probably a race between start-stop-daemon running node and writing that pidfile and /bin/sh forking, execing, and forking again to exec cat $MYAPP_PIDFILE.
The right way to do this is to rewrite your post-start as such:
post-start script
for i in 1 2 3 4 5 ; do
if [ -f $MYAPP_PIDFILE ] ; then
echo ...
exit 0
fi
sleep 1
done
echo "timed out waiting for pidfile"
exit 1
end script
Its worth noting that in Upstart 1.4 (included first in Ubuntu 12.04), upstart added logging ability, so there's no need to redirect output into a special log file. All console output defaults to /var/log/upstart/$UPSTART_JOB.log (which is rotated by logrotate). So those echos could just be bare echos.

Resources