Bash-script as linux-service won't run, but executed from terminal works perfectly

8

3

I have custom script to mount google drives.
Part of this script, is following code:

if [ ! "$(which google-drive-ocamlfuse)" ]
then
    echo "Install google-drive-ocamlfuse first!"
    exit 1
fi

Executed from terminal, works like charm.
So, I configured it as service:

[Unit]
Description=Mount and umount google drives

[Service]
User=<usernamehere>
Type=oneshot
RemainAfterExit=true
ExecStart=/home/<usernamehere>/mybscripts/gdrivemounter.sh -m
ExecStop=/home/<usernamehere>/mybscripts/gdrivemounter.sh -u
Environment="DISPLAY=:0"
Environment="XAUTHORITY=/home/<usernamehere>/.Xauthority"

[Install]
WantedBy=graphical.target

Unfortunately, I see exit code: "Install google-drive-ocamlfuse first!" when I checking service status.

Command which google-drive-ocamlfuse under user and root gives me valid path:

$ which google-drive-ocamlfuse
/home/<usernamehere>/.opam/default/bin/google-drive-ocamlfuse

Where is the problem?

rah606

Posted 2019-09-28T12:19:04.853

Reputation: 93

I don't know how your service files are configured but I suspect that the description needs to be in quotes? Description="Mount and umount google drives" maybe – djsmiley2k TMW – 2019-09-28T12:21:13.767

Checking the redhat documentation it seems that isn't the case. And re-reading your question it can't be the issue as the script is being executed. I'm presuming for 'user' you have it set to run as your own user? If not, you need to check that the user you're running it as, has access to google-drive-ocamlfuse. This may require making sure it's on their $PATH which might be different to the $PATH you have when you login on an interactive shell. – djsmiley2k TMW – 2019-09-28T12:23:37.680

@djsmiley2k what is important: without code in first block, script working as service perfectly. – rah606 – 2019-09-28T12:26:19.150

1That's very weird, can you add echo $PATH to the error block, to see what path is set to at that time. – djsmiley2k TMW – 2019-09-28T12:28:35.883

Note you can use the bash builtin type instead of calling out to which. – glenn jackman – 2019-09-28T12:37:21.543

1As a side note, this should probably run as user systemd instance. It will assume environment of your user by default. Put it in ~/.config/systemd/user/ and run with systemctl --user start <service>. (Note: I believe not all distributions enable user systemd instance by default) – Mirek Długosz – 2019-09-29T09:10:52.187

@MirekDługosz that could be a full answer to be honest, as it'd 'fix' the issue by setting $PATH correctly. – djsmiley2k TMW – 2019-09-29T12:43:03.030

Answers

12

The problem is that, when the script runs as a service, it does not run as "you": it does not have your environment. Specifically, it does not have your PATH variable.

Either add /home/<usernamehere>/.opam/default/bin to the PATH in your script, or simply hardcode the full path for that program.

glenn jackman

Posted 2019-09-28T12:19:04.853

Reputation: 18 546

While I think this is the issue, it'd be better to add the path via the service file using environment, as this way it'll only modify $PATH while running the service. Your way will modify it for any user running the script, and make the check entirely pointless. – djsmiley2k TMW – 2019-09-28T12:31:32.057

1IMO the check is already not very valuable. Just set up the PATH and execute the program. If it's not there, bash will give you a descriptive error message. I would be surprised if there are other users on the OP's system (this is exactly the kind of script I've written on my own laptop). – glenn jackman – 2019-09-28T12:34:49.727

3

The most likely reason is that the directory containing google-drive-ocamlfuse is in the PATH of your login shell, but not in the standard PATH used by systemd.

Just add a line like this at the beginning of your script:

PATH=$PATH:/path/to/google-drive-ocamlfuse

RalfFriedl

Posted 2019-09-28T12:19:04.853

Reputation: 1 370

While I think this is the issue, it'd be better to add the path via the service file using environment, as this way it'll only modify $PATH while running the service. Your way will modify it for any user running the script, and make the check entirely pointless. – djsmiley2k TMW – 2019-09-28T12:30:16.120

You assume the point is to test whether the program in the current PATH. More likely the point is to find out whether the program is present or not. – RalfFriedl – 2019-09-28T12:35:33.743

You presume the script is running on a single user system. Adding a $PATH to another users' home directory isn't going to go well for you if anyone else needs to run this script. – djsmiley2k TMW – 2019-09-28T12:37:13.943

I noticed that the script as already in some user`s home directory, so it is probably not intended to be executed by other users. – RalfFriedl – 2019-09-28T12:43:05.373

1

Note: I've left this answer 'as is' but the only relevant part is how to set the environment via the service file, rather than directly in the script. Setting a new $PATH in the script won't persist after the script has finished running.

In reference to the other answers, please don't pollute your $PATH by editing your script, when in fact it works if ran by the correct user. If you must edit it directly in the script, put it back after by restoring the original $PATH.

I think the issue lies with the fact that /etc/profile isn't processed by systemd services, and so it hasn't for whatever reason got access (or an updated $PATH) for the executable required.

To test this you could echo out $PATH within the error block, and if it IS missing, then add it directly into the Environment variable within the systemd service file:

[Service]
Environment=PATH=/home/someUser/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

This way, the path is only updated for the script while it runs, it doesn't modify it for users who might not expect it to be modified..

djsmiley2k TMW

Posted 2019-09-28T12:19:04.853

Reputation: 5 937

3Environment is per-process – any changes done within the script will be lost once the script exits, so "putting it back" is completely redundant. – user1686 – 2019-09-28T13:26:15.070

Ah I was thinking of export... – djsmiley2k TMW – 2019-09-28T14:33:38.497

1Still applies even to export. Child processes of that script (or interactive shell) will inherit the exported environment variables; all other processes will not see the changes at all. – user1686 – 2019-09-28T16:52:36.497

@grawity yeah, I read that too now, I guess my answer is not really adding anything useful other than maybe the systemd file change. I'll add a a comment to the answer to indicate so, thanks for helping me learn :) – djsmiley2k TMW – 2019-09-29T12:38:48.860

1

Thank you all for solutions. Each is important for me and helpful - again I learned something new. At the end I decided to install google-drive-ocamlfuse from deb, instead via opam. It is better to install gdo in path available for all users. Due to this, additional configuration of $PATH is not necessary.

rah606

Posted 2019-09-28T12:19:04.853

Reputation: 93

I'm still wondering, did configuring the $PATH by which ever method you choose, fix the issue? If so, and the script is being ran as your user, that's a very interesting finding. – djsmiley2k TMW – 2019-09-29T12:42:03.257

Generally use the system package manager to install things unless you have very good reason to do it another way. This mean that the maintenance burden moves from you to the operating system maintainers, so you can do something else. – Thorbjørn Ravn Andersen – 2019-09-29T17:05:51.600