Program my_prog
is to be launched after boot. It creates a Unix domain socket /tmp/my_prog.sock
owned by root:root
.
I am trying to do the followings:
www-data:www-data
after it is created.This is my first version of unit file my_prog.service
:
[Unit]
Description=My Program
After=network.target
[Service]
ExecStart=/usr/local/bin/my_prog
ExecStartPost=chmod www-data:www-data /tmp/my_prog.sock
ExecStopPost=rm -f /tmp/my_prog.sock
[Install]
WantedBy=multi-user.target
This version has two problems:
The owner of /tmp/my_prog.sock
is never changed - always root:root
.
/tmp/my_prog.sock
is never removed after this service is stopped.
I guess it is commands chmod
and rm
getting executed too soon that gives me such unexpected results:
chmod
runs before my_prog
finishes creating the socket file, andrm
runs before my_program
exits (my_program
prohibits its socket file from being deleted when it is running?).What follow are my second version, which fails to give me correct results, either:
file my_prog.service
:
[Unit]
Description=My Program
After=network.target
[Service]
ExecStart=/usr/local/bin/my_prog
[Install]
WantedBy=multi-user.target
file my_prog-socket.path
:
[Unit]
Description=My program - notify socket existence
[Path]
PathExists=/tmp/my_prog.sock
file my_prog-socket.service
:
[Unit]
Description=My program - change owner and remove socket
[Service]
ExecStart=chown www-data:www-data /tmp/my_prog.sock
ExecStopPost=rm -f /tmp/my_prog.sock
I have run out of all tricks. What's wrong with my unit files? Is there more elegant design than above?
Thanks!
P.S.: For those who are interested, this legacy version /etc/init.d/my-prog
works as expected, at least:
#!/bin/sh
### BEGIN INIT INFO
# Provides: my-program
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: My Program
# Description: My Program
### END INIT INFO
PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/local/bin/my_prog
NAME=my-program
DESC="My Program"
SCRIPTNAME=/etc/init.d/$NAME
PIDFILE=/var/run/my-prog.pid
SOCKET_FILE="/tmp/my-prog.sock"
test -x $DAEMON || exit 0
grant_socket_access()
{
#Wait program to create socket.
count=1
while [ "$count" -lt "50" ]
do
if [ -S $SOCKET_FILE ]
then
chown www-data:www-data $SOCKET_FILE
return 0
fi
sleep 0.2
count=`expr $count + 1`
done
echo >&2 "$NAME fails to grant access to Unix socket file: $SOCKET_FILE"
return 1
}
. /lib/lsb/init-functions
case "$1" in
start)
log_daemon_msg "Starting $DESC" $NAME
rm -f $SOCKET_FILE
if start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -b -m
then
grant_socket_access
else
rm -f $SOCKET_FILE
fi
log_end_msg $?
;;
stop)
log_daemon_msg "Stopping $DESC" $NAME
rm -f $SOCKET_FILE
if start-stop-daemon --stop --retry TERM/10/KILL/5 --quiet --pidfile $PIDFILE --exec $DAEMON --remove-pidfile
then
log_daemon_msg "$DESC" "$NAME stopped"
log_end_msg 0
else
log_end_msg 1
fi
;;
reload|force-reload)
log_daemon_msg "Reloading $DESC" $NAME
rm -f $SOCKET_FILE
if start-stop-daemon --stop --signal HUP --quiet --pidfile $PIDFILE --exec $DAEMON
then
grant_socket_access
log_end_msg $?
else
log_end_msg 1
fi
;;
restart)
log_daemon_msg "Restarting $DESC" $NAME
$0 stop
$0 start
;;
status)
status_of_proc -p "$PIDFILE" "$DAEMON" "$NAME" && exit 0 || exit $?
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload|status}" >&2
exit 1
;;
esac
exit 0
Edit
Following the recipe kindly provided by @Mark Stosberg, I have modified my original first version to have /bin/chown
and /bin/rm
just now.
I get the desired result from line ExecStopPost=/bin/rm -f /tmp/my_prog.sock
in the new version. However, ExecStart=/bin/chown www-data:www-data /tmp/my_prog.sock
outputs this error:
chown[8388]: /bin/chown: connot access '/tmp/my_prog.socket'
Running your script through your systemd-analyze verify ./your-file.service
reveals the problems:
[/home/mark/tmp/t.service:7] Executable path is not absolute, ignoring: chmod www-data:www-data /tmp/my_prog.sock
[/home/mark/tmp/t.service:8] Executable path is not absolute, ignoring: rm -f /tmp/my_prog.sock
The documentation in man systemd.service
documents the requirement that the executable paths must be absolute.
Your error refers to a file with a .socket
extension, but your example shows a .sock
extension. Confirm that you are using .sock
or .socket
consistently everywhere.
If your service doesn't need to run as root, you can improve the security and avoid the need to chown
, by using the User=
and Group=
directives to run the service as a different user. This will create a socket owned by that user instead of root.