22

I am curious whether I can print out fully expanded ExecStart/ExecStop command line. Consider following example:

ExecStart=/usr/bin/java $OPTS_COMMON $OPTS $OPTS_LOG $OPTS_DEBUG some.class.Start --param1 ${PARAM1} --param2 ${PARAM2}

I am having quite long command lines with a lot of environment variables involved. If some of the variables becomes wrong (for example by drop-in configuration), service might not start at all. However I do not see fully expanded line with substituted envs anywhere and I struggle to find out what is wrong.

I had no luck googling this and so far the only possibility I found is to modify unit file to run /usr/bin/echo instead of service itself. But that is a bit tiresome. Or even more annoying solution - check every environment variable one-by-one.

Is there some way how to force systemd to show me what is actually attempted to be run?

pystole
  • 355
  • 2
  • 3
  • 8
  • I did write a detailed set of steps for working out what the command would be and general debugging tips, in case anybody still needs help: https://containersolutions.github.io/runbooks/posts/linux/debug-systemd-service-units/ – Gerry Jul 03 '20 at 12:34

3 Answers3

20

Unfortunately there is no built in way. To see the final ExecStart you can turn on debugging. Edit the file /etc/systemd/system.conf and set the LogLevel= to debug. Then you will see something like:

java.service About to execute: /usr/bin/java $OPTS_COMMON... This doesn't solve your problem but it is good to see the systemd's specifier replacement. https://www.freedesktop.org/software/systemd/man/systemd.unit.html(specifiers)

But if you really want to get to the bottom of argument replacement you need to look in to here: https://github.com/systemd/systemd/blob/7ce9cc154576e342015eab8c1500790a9ededc01/src/core/execute.c#L2570

Umut
  • 411
  • 3
  • 3
  • I was a bit afraid that there is no way how to do it. :/ Thanks anyway. – pystole Sep 21 '16 at 10:57
  • 3
    I found that `LogLevel=debug` as mentioned above does work, but not until I run this command to reload the systemd manager configuration.: `systemctl daemon-reload`. – CODE-REaD May 01 '20 at 02:11
5

Instead of using the command line to execute, use a wrapper script (or binary) with the same command and parameters. Then the wrapper script logs the parameters and then executes the real command.

Like this:

ExecStart=/path/to/wrapper /usr/bin/java $OPTS_COMMON $OPTS $OPTS_LOG $OPTS_DEBUG some.class.Start --param1 ${PARAM1} --param2 ${PARAM2}

The wrapper script itself could be:

#!/bin/sh
LOGFILE=/some/safe/file
for param
do
    echo "param: $param"
done > $LOGFILE
exec "$@"
U. Windl
  • 286
  • 2
  • 13
2

In *.service file in section [Service]

ExecStartPre=/bin/bash -l -c 'echo "$OPTS_COMMON">/tmp/options.debug'
greenif
  • 121
  • 2
  • Didn't work for me. The file has no content. – Max Leske Apr 25 '20 at 10:42
  • 1
    the single ' quotes around the command prevent the variable substitution by bash. Try it with the ' and " positions swapped. bash -l -c "echo '$OPTS_COMMON'>/tmp/options.debug" instead. Alternatively, use " throughout but escape the internal pair. bash -l -c "echo \"$OPTS_COMMON\">/tmp/options.debug" – user207998 Apr 29 '20 at 13:38
  • Or something like : "echo $OPTS_COMMON | tee /tmp/options.debug" – irdroid3 Dec 19 '20 at 21:41