custom linux daemon won't stop using "service stop" - python

I've written a custom python daemon that runs as a service via an init.d script on ubuntu 14.04. Starting the service works fine, but when I try to do "service monitor stop", the daemon is not terminated. I'm using pyinotify to daemonize a file watcher for changes.
Within the init.d script:
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Monitor files"
NAME=monitor
DAEMON=/usr/bin/python
DAEMON_ARGS="/home/user/python/monitor.py"
PIDFILE=/home/user/logs/monitor.pid
LOGFILE=/home/user/logs/monitor.log
SCRIPTNAME=/etc/init.d/$NAME
...
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
RETVAL="$?"
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"
echo "done"
}
...
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
...
To ensure the daemon handles SIGERM properly, I can run it by hand:
bash$ /usr/bin/python /home/user/python/monitor.py
bash$ kill -Term PID
The daemon successfully handles the SIGTERM and exits properly.
I can't seem to figure out why it doesn't handle it when I do "service monitor stop" though.

Check that the process $NAME is correct, as delivered to the start-stop-daemon --stop command. I just encountered this issue because a process I was running ended up getting a different name whenever it forked its daemon. Try running this to see the process command name:
ps -o comm= $(cat /home/user/logs/monitor.pid)
I bet yours outputs this (instead of monitor):
python
Then change your stop command to look like this, where you substitute python in place of $NAME:
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name python

Related

PyQt: How to run GUI on Raspberry Pi desktop startup?

Dear Stackoverflow community,
I am struggling with running a python script that executes a PyQt5 GUI on desktop startup of Raspberry Pi 3B with Raspbian Jessie.
What do I have so far?
Python script with shebang #!/usr/bin/env python3 in first line (python3 --version is 3.4.2) running the GUI without any problems
Shell script (.sh) that is able to execute the GUI with the following lines:
#!/bin/bash
python3 GUI.py
Information that may help:
If I place both files in the same directory somewhere, the Shell script starts the GUI, but if they are on the desktop, it doesn't.
Automatic login to desktop is enabled.
Thank you in advance for any help.
RaspiManu
UPDATE:
I solved my Problem with a lot of testing and posted an answer for other users.
After a lot of testing, I figured it out myself. Here's how it worked for me...
Create autorun-file:
2.1 LXTerminal: cd /home/pi/.config/autostart
2.2 LXTerminal: sudo nano pythonscript.desktop
2.3 pythonscript.desktop:
[Desktop Entry]
Version=1.0
Name=YourName
Comment=Your comment
Exec=/home/pi/pythonscript.py -nograb #-nograb for comboBox on touch Screen
Icon=/usr/share/pixmaps/python.xpm
Path=/home/pi/
Terminal=false
StartupNotify=true
Type=Application
Categories=Utility;Application;
2.4 Ctrl+O, Ctrl+X, sudo reboot
Good to know:
It is important, that you can't use just any path to your script. The script has to be directly in the /home/pi/ directory, so you would use Exec=/home/pi/pythonscript.py in the autorun-file (.desktop). I also learned, that if your script loads for example an image with PIL, this image has to be somewhere else, maybe on your desktop, because it can't be opened out of the /home/pi/ directory.
If your GUI has a comboBox and you are using a touch screen, the comboBox might make your whole GUI unuseable after you touched it. Using Exec=/home/pi/pythonscript.py -nograb solves this problem.
StartupNotify=true is important for starting GUI scripts.
Hope this helps,
RaspiManu
You can make a background service that runs on startup, by following this link
Service method
and By appending this line
service yourdaemon start
in /etc/rc.local
assuming your service name is 'yourdaemon'
Caution: Use the root previleges
Example service file
#! /bin/sh
### BEGIN INIT INFO
# Provides: yourdaemon
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Your Daemon
# Description: Your Daemon
### END INIT INFO
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Your Daemon"
NAME=yourdaemon
DAEMON=/hannext/yourdaemon.py # Path to your python file
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
LOGFILE=/var/log/snc/$NAME.log
. /lib/lsb/init-functions
do_start()
{
echo "$(date +%F) $(date +%T) DAEMON : Starting $DESC service" >> $LOGFILE
start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --startas $DAEMON --make-pidfile --background
}
do_stop()
{
echo "$(date +%F) $(date +%T) DAEMON : Stopping $DESC service" >> $LOGFILE
start-stop-daemon --stop $DAEMON --quiet --oknodo --pidfile $PIDFILE
rm -f $PIDFILE
}
#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
return 0
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
exit 3
;;
esac
:
save it by the name of 'yourdaemon' in /etc/init.d/ and make it executable using
chmod +x yourdaemon

Linux start-stop-daemon directory error calling shell/python script

I am just getting acquainted with Linux and I cannot seem to get the start-stop-daemon to run a python script due to directory issues. In a linux file structure I have the files:
~/test.txt
THIS LINE IS A TEST
~/test.py
#!/usr/bin/python
import time
with open("test.txt") as f:
while True:
try:
print("Hello World")
print(f.readline())
time.sleep(2)
except KeyboardInterrupt:
f.close()
break
~/test.sh
#!/bin/bash
echo "SHELL SCRIPT SUCCESS" > /var/log/test.log
cd ~/
./test.py > /var/log/test.log
Upon calling sudo bash ~/test.sh from any directory the test.log is populated as expected with the stdout originating from test.py. For some reason, starting the following start-stop-daemon service script WILL generate a test.log but does NOT populate it with the stdout:
/etc/init.d/test
#!/bin/sh
### BEGIN INIT INFO
# Provides: Python test script
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Prints out daemonized argument
# Description: Creates output of argument
### END INIT INFO
DAEMON_DIR=/home/alex
DAEMON=$DAEMON_DIR/test.sh
DAEMON_NAME=test
DAEMON_OPTS="hello"
DAEMON_USER=root
PYTHON=/usr/bin/python
PIDFILE=/var/run/$DAEMON_NAME.pid
. /lib/lsb/init-functions
do_start () {
log_daemon_msg "Starting system $DAEMON_NAME daemon"
#start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --user $DAEMON_USER --exec $PYTHON --startas $DAEMON
start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --chuid $DAEMON_USER --startas /bin/bash /home/alex/test.sh
log_end_msg $?
}
do_stop () {
log_daemon_msg "Stopping system $DAEMON_NAME daemon"
start-stop-daemon --stop --pidfile $PIDFILE --retry 10
log_end_msg $?
}
case "$1" in
start|stop)
do_${1}
;;
restart|reload|force-reload)
do_stop
do_start
;;
status)
status_of_proc "$DAEMON_NAME" "$DAEMON" && exit 0 || exit $?
;;
*)
echo "Usage: /etc/init.d/$DAEMON_NAME {start|stop|restart|status}"
exit 1
;;
esac
exit 0
Is this a directory issue that can be addressed within the start-stop-daemon?
Alternatively I'd be open to other methods of script servicing that can persist through a cold boot (i.e. no cron jobs)
Try calling cd using an absolute path, for example /home/alexjg/ instead of ~/; the reason it was broken before is that in your example you're using sudo which keeps the home directory of the user running it. However when you're calling the bash script from init it will use root's home directory instead which doesn't contain test.py.
The file is created because the redirection is still succeeding; however because starting Python failed there was no output.

Python script on boot Linux

I would like to launch my python program (Graphical User Interface) on startup in Linux (Raspbian on a Raspberry PI).
I've made an initscript to launch my Python program, and I put it in the etc/init.d map.
I enabled it with the update-rc.d command. It all works fine.
But my Python script won't start with the following code in the initscript:
#!/bin/bash
### BEGIN INIT INFO
# Provides: GUI
# Required-Start:
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: This is a test daemon
# Description: This is a test daemon
# This provides example about how to
# write a Init script.
### END INIT INFO
case $1 in
start)
python3 /home/pi/Desktop/GUI/GUI.py
;;
stop)
# Stop the daemon.
if [ -e $PIDFILE ]; then
status_of_proc -p $PIDFILE $DAEMON "Stoppping the $NAME process" && status="0" || status="$?"
if [ "$status" = 0 ]; then
start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE
/bin/rm -rf $PIDFILE
fi
else
log_daemon_msg "$NAME process is not running"
log_end_msg 0
fi
;;
restart)
# Restart the daemon.
$0 stop && sleep 2 && $0 start
;;
status)
# Check the status of the process.
if [ -e $PIDFILE ]; then
status_of_proc -p $PIDFILE $DAEMON "$NAME process" && exit 0 || exit $?
else
log_daemon_msg "$NAME Process is not running"
log_end_msg 0
fi
;;
reload)
# Reload the process. Basically sending some signal to a daemon to reload
# it configurations.
if [ -e $PIDFILE ]; then
start-stop-daemon --stop --signal USR1 --quiet --pidfile $PIDFILE --name $NAME
log_success_msg "$NAME process reloaded successfully"
else
log_failure_msg "$PIDFILE does not exists"
fi
;;
*)
# For invalid arguments, print the usage message.
echo "Usage: $0 {start|stop|restart|reload|status}"
exit 2
;;
esac
The problem is that when the init script run, there is not graphical interface available. Instead of using a init script, try configuring your application to run on X startup.
First add the command line to start your GUI app to ~/.xinitrc
# ~/.xinitrc
exec python3 /home/pi/Desktop/GUI/GUI.py
And then start the X server
startx

init.d script does not work unless the same script is executed from a local directory first

I have run into a problem that I still haven't been able to solve despite hours of efforts including searching numerous Linux forums. My init.d script is based on a standard script to launch a python script as a service. I have used this script for other services without any problems, but not this time.
To make a long story short, my problem is like follows:
The script works fine if I execute it in my home directory. I can start and stop the service etc.
If I execute the script in /etc/init.d it also works fine, provided I have run it once before in my home directory. If I try to execute the script immidiately after reboot, nothing happens. Consequently the service does not start after reboot. Running the script with service "script_name" start/stop/restart follows the same pattern. Ok if I have executed the script from my home directory first, otherwise nothing happens.
I get a feeling it is related to the environment, but if I check with printenv before and after executing the script from my home directory I can't see anything has changed. There are no other things that I believe is changed by running the script from my home directory. I run the script with sudo.
Since the script is exactly the same as I use on another Rasp except for the name of the Python script (and it works there...), I hardly believe there is something wrong in the script.
EDIT: I just noticed I can log off/on and this does not affect the status. So I can still run it in /etc/init.d if I've made it work by executing it once from my home directory since last reboot. Here comes the script:
#! /bin/bash
### BEGIN INIT INFO
# Provides: bbb_domoticz
# Required-Start: $network $remote_fs $syslog
# Required-Stop: $network $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: BehovsBoBox control script
# Description: This daemon will start the BehovsBoBox Control system
### END INIT INFO
# Do NOT "set -e"
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
DESC="BehovsBoBox Control System"
NAME=bbb_domoticz.py
USERNAME=pi
DAEMON=/home/pi/bbb_addon/$NAME
DEAMON_OPTS=""
PIDFILE=/var/run/bbb_domoticz.pid
#
SCRIPTNAME=/etc/init.d/bbb_domoticz.sh
#
# Modified to force deamon to execute in background
#
# Exit if the package is not installed
# [ -x "$DAEMON" ] || exit 0
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
VERBOSE=""
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
if [ -e $PIDFILE ]
then
pid=$(<$PIDFILE)
ps p $pid > /dev/null || rm -f $PIDFILE
fi
# start-stop-daemon --chuid $USERNAME --start --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
# || return 1
# echo "OK to start"
start-stop-daemon --start --make-pidfile --pidfile $PIDFILE --background --startas $DAEMON -- $DEAMON_OPTS || return 2
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
[ "$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
# echo "status $?"
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
restart)
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|status|restart}" >&2
exit 3
;;
esac
:

Python script as daemon in ubuntu

I created a daemon to run a python script. but it stops whenever i logout from my ubuntu machine.
DAEMON=sudo python /var/www/some_dir/my_python.py
ARGS=/var/www/some_dir/my_python.py
PIDFILE=/var/www/some_dir/my_python.pid
test -x $DAEMON || exit 0
#set -e
case "$1" in
start)
echo -n "Starting $DESC: "
start-stop-daemon --start --pidfile $PIDFILE --exec $DAEMON &
echo "$NAME."
;;
stop)
echo -n "Stopping $DESC: "
start-stop-daemon --stop --pidfile $PIFDILE --exec $DAEMON
echo "$NAME."
;;
restart|force-reload)
echo -n "Restarting $DESC: "
start-stop-daemon --stop --pidfile $PIDFILE --exec $DAEMON
sleep 1
start-stop-daemon --start --pidfile $PIDFILE --exec $DAEMON &
echo "$NAME."
;;
*)
N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|restart|force-reload}" >&2
exit 1
;;
esac
exit 0
can anyone tell me how can i do it.
It's a long time since this question was asked, but I came across this situation today.
To start the process in the background, use
start-stop-daemon -Sbm --pidfile $PIDFILE --exec $DAEMON
To stop it:
start-stop-daemon -K --pidfile $PIDFILE
From the start-stop-daemon man page:
-b , -background
Force the daemon into the background. Some daemons don't create
pidfiles, so a good trick is to get the daemon to run in the
foreground, and use the this option along with -m , -make-pidfile to
create a working pidfile.
-m , -make-pidfile
Saves the pid of the daemon in the file specified by the -p, -pidfile
option. Only useful when used with daemons that run in the foreground
and forced into the background with the --b, -background option.
Try to remove & from your start-stop-daemon invocations. Also, you should read how to write proer initscripts because there are several other errors in your initscript.

Categories