[systemd-devel] Problem converting an rc script

Mantas Mikulėnas grawity at gmail.com
Sun Apr 7 12:45:31 PDT 2013


On Sun, Apr 7, 2013 at 10:21 PM, John Lane <systemd at jelmail.com> wrote:
> I have been trying to replace an rc script with a systemd unit file. It is
> for an rvm (ruby version manager) environment and it starts a documentation
> web server. I tried to create a service unit thus:
>
> [Service]
> Type=forking
> User=rvm
> ExecStartPre=/bin/bash --login /etc/profile.d/rvm.sh
> ExecStartPre=/usr/local/rvm/bin/rvm use %i
> ExecStart=/${GEM_HOME}/bin/gem server --daemon --port 8808
>
> The rvm environment needs to be initialised (by running
> /etc/profile.d/rvm.sh) and this needs to happen in a bash login shell (this
> is due to the design of rvm).
>
> I think the ExecStart* lines in the above example are each invoked in a
> separate environment (so the initialisation performed by the first is lost
> before the second and third items are processed). Is this right or do I
> misunderstand?

That's right, but not because of systemd.

When you run "bash /etc/profile.d/rvm.sh", it works in non-interactive
mode: first it interprets the given script, then simply exits. This is
the same regardless of where and how it is run. Since profile.d/rvm.sh
just sets environment variables, and those do not propagate upwards,
the entire command has no effect.

In actual login sessions, your shell starts and "sources"
/etc/profile, which then "sources" the profile.d scriptlets – instead
of running a separate copy of bash for them. Since systemd is not a
shell and does not understand (ba)sh syntax, the same thing cannot be
done here, at least not directly.

> My question is to ask how would I create a unit that starts a service in an
> properly initialised environment when the only way to initialise that
> environment is to run a bash setup script that requires it to be run in a
> login shell ?

My first thought is "fix the damn setup script". Surely rvm already
has a way to be used non-interactively?...

Actually – is the "login shell" requirement imposed by rvm.sh itself
checking for that, or simply by the fact that rvm.sh is in
/etc/profile.d? — If it's the former, then rvm is broken, but if it's
the latter, then it's not a real requirement as rvm.sh could be
sourced manually without relying on /etc/profile to do it.

It might be that all you need is to set $PATH and $GEM_HOME
environment variables using the Environment= property (or
EnvironmentFile=.)

(But note that you cannot use variables in the zeroth argument for ExecStart.)

> My solution that works is to use a unit to invoke a bash script that
> performs the initialisation and then starts the service. But I feel this
> somewhat negates the benefits of systemd not being based on shell scripts.
> I'd like to try and get it to work with a unit file and no supporting
> scripts, if this is possible.

It doesn't completely negate the benefits, as the script only performs
initialization for your service – you still get the advantages of
systemd enforcing dependencies, starting multiple services in
parallel, process tracking, and pretty much everything else. The only
significant downsides I can think of are having to load heavy
/bin/bash, and similarly heavy rvm.

I use rbenv to manage different Ruby versions, and while it probably
doesn't offer the same functionality as rvm, it's also much simpler to
use: it only needs <rbenv-path>/shims to be added to $PATH.

--
Mantas Mikulėnas <grawity at gmail.com>


More information about the systemd-devel mailing list