23

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?

1

3 Answers 3

22

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


2
  • I was a bit afraid that there is no way how to do it. :/ Thanks anyway.
    – pystole
    Sep 21, 2016 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 1, 2020 at 2: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 "$@"
2

In *.service file in section [Service]

ExecStartPre=/bin/bash -l -c 'echo "$OPTS_COMMON">/tmp/options.debug'
3
  • Didn't work for me. The file has no content.
    – Max Leske
    Apr 25, 2020 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, 2020 at 13:38
  • Or something like : "echo $OPTS_COMMON | tee /tmp/options.debug"
    – irdroid3
    Dec 19, 2020 at 21:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .