0

I have this init.d script (/etc/init.d/ctrlme):

#!/lib/init/init-d-script

### BEGIN INIT INFO
# Provides:          ctrlme
# Required-Start:    $local_fs $remote_fs $network
# Required-Stop:     $local_fs $remote_fs $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: ctrlme
# Description:       ctrlme
### END INIT INFO

# sudo cp -v /home/gigikent/bin/init.d-services/ctrlme /etc/init.d/; sudo chown root: /etc/init.d/ctrlme
#
# https://www.pks.mpg.de/~mueller/docs/suse10.1/suselinux-manual_en/manual/sec.boot.init.html   
#

NAME=ctrlme
PIDFILE=/run/ctrlme.pid
DAEMON=/bin/bash -c '/home/gigikent/x.sh ctrlme'
DESC=ctrlme

# . /lib/lsb/init-functions
# 
# case "$1" in
#   start)
#         /home/gigikent/x.sh ctrlme
#     ;;
#   stop|restart|force-reload) 
#         exit 0
#     ;;
#   *) echo "Usage: $0 {start|stop|restart|force-reload}" >&2; exit 1 ;;
# esac

which when started fails with:

Jun 16 18:57:13 gigikent.go.ro ctrlme[28454]: /lib/init/init-d-script: 20: /etc/init.d/ctrlme: -c: not found
Jun 16 18:57:13 gigikent.go.ro systemd[1]: ctrlme.service: Succeeded.
-- Subject: Unit succeeded
-- Defined-By: systemd
-- Support: http://www.ubuntu.com/support
-- 
-- The unit ctrlme.service has successfully entered the 'dead' state.

Running /bin/bash -c '/home/gigikent/x.sh ctrlme' command works as expected.
Why this happens and how should I solve the problem?

System info:
Ubuntu 19.04

Adrian
  • 701
  • 1
  • 8
  • 29
  • 4
    Quote your variables (assignments) !! Use: DAEMON="/bin/bash -c '/home/adr/x.sh ctrlme'" –  Jun 16 '19 at 16:37
  • 3
    Please paste your script in https://www.shellcheck.net/ and you will find several issues (and a simple description of what the problem is). –  Jun 16 '19 at 16:41
  • As I already mentioned the x.sh script is running fine when executed directly. When using DAEMON="..." I get basename: extra operand ‘'/home/adr/x.sh’. – Adrian Jun 16 '19 at 17:55
  • 1
    When executed directly you are using a bash shell: /bin/bash -c '/home/adr/x.sh ctrlme' but the shell-bang (Please use shellcheck to confirm) is invalid, or (at least) doesn't set the shell to bash. –  Jun 16 '19 at 18:12
  • Are you sure? check this: sudo grep -nr '#!/lib/init/init-d-script' /etc/init.d yields /etc/init.d/whoopsie:1:#!/lib/init/init-d-script – Adrian Jun 16 '19 at 18:14
  • Yes, I am sure. The init-d-script is not a shell. I invite you to learn the basics. –  Jun 16 '19 at 22:22
  • What happens when you execute your script as: /home/adr/x.sh ctrlme –  Jun 16 '19 at 22:25
  • Running /home/adr/x.sh ctrlme works as expected; be aware that x.sh starts with #!/bin/bash. I again mention that running /bin/bash -c '/home/adr/x.sh ctrlme' also works as expected. I agree #!/lib/init/init-d-script (used by /etc/init.d/ctrlme) is odd but on the other hand seems to function well. – Adrian Jun 17 '19 at 11:11
  • Can a shell script be an interpreter? – ctrl-alt-delor Jun 17 '19 at 23:02
  • @ctrl-alt-delor according to man init-d-script, yes the script can be used as an interpreter. “init-d-script - interpreter for short and simple init.d scripts. … This is a simple example on how init-d-script can be used to start and stop a daemon with PID file support: #!/lib/init/init-d-script …” – ctrl-alt-delor Jun 17 '19 at 23:06

2 Answers2

3
DAEMON=/bin/bash -c '/home/adr/x.sh ctrlme'

This should be:

DAEMON="/bin/bash" 
DAEMON_ARGS="'/home/adr/x.sh ctrlme'"

or, better yet:

DAEMON="/home/adr/x.sh" 
DAEMON_ARGS="ctrlme"

Further reading

JdeBP
  • 68,745
0

Analyzing the /lib/init/init-d-script source one observes:

do_start_cmd() {
    start-stop-daemon --start --quiet ${PIDFILE:+--pidfile ${PIDFILE}} \
        $START_ARGS \
        --startas $DAEMON --name $NAME --exec $DAEMON --test

which with scripts (e.g. bash scripts) this won't work because according to http://man7.org/linux/man-pages/man8/start-stop-daemon.8.html DAEMON should be a pathname:

-a, --startas pathname
        With --start, start the process specified by pathname.  If not
        specified, defaults to the argument given to --exec.

Also one could just compare the above usage of start-stop-daemon with the one from /lib/lsb/init-functions, e.g.:

start_daemon () {
    ...
    exec="$1"; shift
    ...
    if [ "$force" ]; then
        /sbin/start-stop-daemon $args \
        --chdir "$PWD" --startas $exec --pidfile /dev/null -- "$@"
    ...

When using start_daemon with e.g.:

start_daemon -p /run/ctrlme.pid /bin/bash /home/adr/x.sh ctrlme

than $exec would be /bin/bash while "$@" would be /home/adr/x.sh + ctrlme meaning that when not having a pathname one would have to use start_daemon() instead of /lib/init/init-d-script with its DAEMON variable.

UPDATE

I let this answer too because better highlights the issue & solution. On the other hand be aware that this part of conclusion is false:

when not having a pathname one would have to use start_daemon() instead of /lib/init/init-d-script

Indeed one could use DAEMON with DAEMON_ARGS as mentioned by the accepted answer. This is true because do_start_cmd() calls start-stop-daemon 2 times where the 2nd call is benefiting of DAEMON_ARGS:

do_start_cmd() {
    start-stop-daemon --start --quiet ${PIDFILE:+--pidfile ${PIDFILE}} \
        $START_ARGS \
        --startas $DAEMON --name $NAME --exec $DAEMON --test > /dev/null \
        || return 1
    start-stop-daemon --start --quiet ${PIDFILE:+--pidfile ${PIDFILE}} \
        $START_ARGS \
        --startas $DAEMON --name $NAME --exec $DAEMON -- $DAEMON_ARGS \
        || return 2
Adrian
  • 701
  • 1
  • 8
  • 29
  • 1
    The script fails because it is missing quotes. It makes the (incorrect?) assumption that the DAEMON variable will contain no spaces. –  Jun 16 '19 at 22:13
  • I tried with quotes too having the same result. Besides, as one can see the documentation asks for a pathname. – Adrian Jun 17 '19 at 10:50