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
Related
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.
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)
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.
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.
I would like to spawn a process suspended, possibly in the context of another user (e.g. via sudo -u ...), set up some iptables rules for the spawned process, continue running the process, and remove the iptable rules when the process exists.
Is there any standart means (bash, corutils, etc.) that allows me to achieve the above? In particular, how can I spawn a process in a suspended state and get its pid?
Write a wrapper script start-stopped.sh like this:
#!/bin/sh
kill -STOP $$ # suspend myself
# ... until I receive SIGCONT
exec $# # exec argument list
And then call it like:
sudo -u $SOME_USER start-stopped.sh mycommand & # start mycommand in stopped state
MYCOMMAND_PID=$!
setup_iptables $MYCOMMAND_PID # use its PID to setup iptables
sudo -u $SOME_USER kill -CONT $MYCOMMAND_PID # make mycommand continue
wait $MYCOMMAND_PID # wait for its termination
MYCOMMAND_EXIT_STATUS=$?
teardown_iptables # remove iptables rules
report $MYCOMMAND_EXIT_STATUS # report errors, if necessary
All this is overkill, however. You don't need to spawn your process in a suspended state to get the job done. Just make a wrapper script setup_iptables_and_start:
#!/bin/sh
setup_iptables $$ # use my own PID to setup iptables
exec sudo -u $SOME_USER $# # exec'ed command will have same PID
And then call it like
setup_iptables_and_start mycommand || report errors
teardown_iptables
You can write a C wrapper for your program that will do something like this :
fork and print child pid.
In the child, wait for user to press Enter. This puts the child in sleep and you can add the rules with the pid.
Once rules are added, user presses enter. The child runs your original program, either using exec or system.
Will this work?
Edit:
Actually you can do above procedure with a shell script. Try following bash script:
#!/bin/bash
echo "Pid is $$"
echo -n "Press Enter.."
read
exec $#
You can run this as /bin/bash ./run.sh <your command>
One way to do it is to enlist gdb to pause the program at the start of its main function (using the command "break main"). This will guarantee that the process is suspended fast enough (although some initialisation routines can run before main, they probably won't do anything relevant). However, for this you will need debugging information for the program you want to start suspended.
I suggest you try this manually first, see how it works, and then work out how to script what you've done.
Alternatively, it may be possible to constrain the process (if indeed that is what you're trying to do!) without using iptables, using SELinux or a ptrace-based tool like sydbox instead.
I suppose you could write a util yourself that forks, and wherein the child of the fork suspends itself just before doing an exec. Otherwise, consider using an LD_PRELOAD lib to do your 'custom' business.
If you care about making that secure, you should probably look at bigger guns (with chroot, perhaps paravirtualization, user mode linux etc. etc);
Last tip: if you don't mind doing some more coding, the ptrace interface should allow you to do what you describe (since it is used to implement debuggers with)
You probably need the PID of a program you're starting, before that program actually starts running. You could do it like this.
Start a plain script
Force the script to wait
You can probably use suspend which is a bash builitin but in the worst case you can make it stop itself with a signal
Use the PID of the bash process in every way you want
Restart the stopped bash process (SIGCONT) and do an exec - another builtin - starting your real process (it will inherit the PID)