21

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

19

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
  • 2
    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
3

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.