Why "StandardInput=tty" in oneshot systemd unit files? - systemd

When googling around for different oneshot systemd unit files I often stumble upon this kind of file:
[Unit]
Description=/etc/rc.local Compatibility
After=network.target
[Service]
Type=oneshot
ExecStart=-/etc/rc.local
ExecStart=-/pathtoyour/script1
ExecStart=-/pathtoyour/script2
TimeoutSec=0
StandardInput=tty <======= WHAT'S THIS?
RemainAfterExit=yes <======= WHAT'S THIS?
[Install]
WantedBy=multi-user.target
See unclear points inline in the example.

StandardInput=tty means that started scripts' standard input is connected to a TTY (by default /dev/console, if no other are specified through "TTYPath=")
RemainAfterExit=yes means that service shall be considered active even when all its processes exited.
See here for more information: https://www.freedesktop.org/software/systemd/man/systemd.directives.html

Related

Centos 7 Created service to run shell script on infinite loop

I have the following script:
whie true
do
#code
sleep 60
done
I then wanted to create a service to start the machine and launch this script as service:
created my.service at /etc/systemd/system/my.service
[Unit]
Description=my Script
[Service]
Type=forking
ExecStart=/bin/script.sh
[Install]
WantedBy=multi-user.target
problem occurs when i systemctl start my.service
it goes to while true loop and hang in there, how can i run this service and make it run in the background ?
According to systemd specification at link. Type=forking is not exactly correct kind of start-up in your case
If set to forking, it is expected that the process configured with
ExecStart= will call fork() as part of its start-up. The parent
process is expected to exit when start-up is complete and all
communication channels are set up. The child continues to run as the
main service process, and the service manager will consider the unit
started when the parent process exits. This is the behavior of
traditional UNIX services. If this setting is used, it is recommended
to also use the PIDFile= option, so that systemd can reliably identify
the main process of the service. systemd will proceed with starting
follow-up units as soon as the parent process exits.
The Type=simple can be correct one. You can try with it
If set to simple (the default if ExecStart= is specified but neither
Type= nor BusName= are), the service manager will consider the unit
started immediately after the main service process has been forked
off. It is expected that the process configured with ExecStart= is the
main process of the service. In this mode, if the process offers
functionality to other processes on the system, its communication
channels should be installed before the service is started up (e.g.
sockets set up by systemd, via socket activation), as the service
manager will immediately proceed starting follow-up units, right after
creating the main service process, and before executing the service's
binary. Note that this means systemctl start command lines for simple
services will report success even if the service's binary cannot be
invoked successfully (for example because the selected User= doesn't
exist, or the service binary is missing).

Starting a systemd service with privileges

I would like systemd to manage the tup monitor, so I wrote a service unit:
[Unit]
Description=Monitor source files for changes
[Service]
Type=simple
ExecStart=/usr/bin/tup monitor -f
ExecStop=/usr/bin/tup stop
WorkingDirectory=/some/dir
StandardOutput=journal+console
StandardError=journal+console
[Install]
WantedBy=multi-user.target
Whereas starting the monitor manually works, trying to do it with systemd fails with the following error:
setpgid: Operation not permitted
tup error: Unable to set process group for tup's subprocesses.
The error originates in this file and seems to be due to systemd not giving the process the capabilities it needs, so I went further:
[Unit]
Description=Monitor source files for changes
[Service]
Type=simple
ExecStart=/usr/bin/tup monitor -f
ExecStop=/usr/bin/tup stop
CapabilityBoundingSet=CAP_SETUID CAP_SETGID
AmbientCapabilities=CAP_SETUID CAP_SETGID
WorkingDirectory=/some/dir
StandardOutput=journal+console
StandardError=journal+console
[Install]
WantedBy=multi-user.target
Still, it doesn't work.
How can I tell systemd to keep the permissions tup requires?
systemd does not restrict any permissions on services by default, so I don’t think that’s the problem. The setpgid(2) manpage mentions three possible conditions for EPERM, though:
An attempt was made to move a process into a process group in a different session, or to change the process group ID of one of the children of the calling process and the child was in a different session, or to change the process group ID of a session leader (setpgid(), setpgrp()).
I think the third one is the most likely cause of the error: tup probably expects to be run from a shell, in which case the shell would be the session leader and tup tries to establish its own process group, but systemd places each service in its own session as part of setting up a clean execution environment for the service (see also daemon(7)), so that step fails.
Unless you can somehow disable that step in tup (it doesn’t need to fork, either, or do a number of other things which systemd makes unnecessary), I think the only workaround would be an ugly hack:
ExecStart=/bin/sh -c '/usr/bin/tup monitor -f'
With this, the session leader will be the shell, not tup, so the setpgid should work again.
Try this
[Unit]
Description=Monitor source files for changes
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/tup monitor -f
ExecStop=/usr/bin/tup stop
CapabilityBoundingSet=CAP_SETUID CAP_SETGID
AmbientCapabilities=CAP_SETUID CAP_SETGID
WorkingDirectory=/some/dir
StandardOutput=journal+console
StandardError=journal+console
[Install]
WantedBy=multi-user.target
I've added After=network.target, this will make sure TUP service starts after the network is fully active and avoid the service failing due to network issues

Running systemd unit directly after local-fs.target and before basic.target

I am creating an embedded system. The embedded system mounts a partition. Directly after mounting the partition, I need to prep an encrypted folder (encfs). I need this to run before any other multi-user.target or graphical.target
Here is my unit file, which works by it's self.
[Unit]
Description=Mx Encrypted Folder
[Service]
Type=oneshot
ExecStart=/usr/bin/mxmountencrypted
RemainAfterExit=true
ExecStop=/usr/bin/mxunmountencrypted
This unit file has no dependencies defined, currently.
Again, I need:
To run this directly after mounting file systems (local-fs.target)
Before any multi-user.target or graphical.target, where must of the services that depend on it will be ran.
It must stop fully before stopping local-fs.target, since there will be a nested mount that needs to be unmounted before systemd can unmount the partition.
I looked into using the systemd.mount item, but it doesn't support encfs.
Based on what you have listed in the requirements:
[Unit]
Description=Mx Encrypted Folder
Requires=local-fs.target
After=local-fs.target
[Service]
Type=oneshot
ExecStart=/usr/bin/mxmountencrypted
RemainAfterExit=true
ExecStop=/usr/bin/mxunmountencrypted
[Install]
WantedBy=multi-user.target
More on systemd Unit files here: https://www.freedesktop.org/software/systemd/man/systemd.unit.html
and systemd Service files: https://www.freedesktop.org/software/systemd/man/systemd.service.html

When running from systemd unit file, unable to open directory

I have a strange problem with Ubuntu 16 and a systemd unit file. I have a service which reads a directory from the local filesystem. The directory is read from an environment variable. Now when I start the service manually (as in: in a ssh session), everything works fine. But when I start the service with the unit file from below, the service is unable to open the storage directory. The error I get is: could nog read contents of storage" message="open /srv/services/poddy/storage: no such file or directory.
Now my question is: does systemd kind of "sandbox" the services?
[Unit]
Description=Poddy service
After=network.target
[Service]
Type=simple
User=myusername
Group=myusername
WorkingDirectory=/srv/services/poddy
ExecStart=/srv/services/poddy/poddy
Restart=always
RestartSec=5
StartLimitInterval=60s
StartLimitBurst=3
Environment=PODDY_STORAGE="/srv/services/poddy/storage"
Environment=PODDY_PORT=8085
[Install]
WantedBy=multi-user.target
Well, I solved it myself. It turns out that quoting the value of an environment var in the systemd unit file eventually double-escaped the value.
So, changing this:
Environment=PODDY_STORAGE="/srv/services/poddy/storage"
into:
Environment=PODDY_STORAGE=/srv/services/poddy/storage
solved my problem :).

Systemd Service not starting up my application

I am new to systemd service scripts. I am trying to start my application from systemd service scripts. My application is a process that in turn invokes multiple process that includes Qt GUI as one of its child. But the service downt starting up my application.
This is how my service looks like:
[Unit]
Description=/etc/rc.d/rc.local Compatibility
ConditionFileIsExecutable=/etc/rc.d/rc.local
After=network.target
[Service]
Type=forking
ExecStart=/etc/rc.d/rc.local start
SysVStartPriority=99
rc.local script looks like:
#!/bin/bash
export DISPLAY=:0
sleep 5
cd /var/MINC3/apps
./PMonTsk
So when try to run the command "systemctl start rc-local.service", the command executes the script but doesnt invoke my application. If I replace some other QT GUI sample application in the plcae of my application in rc.local, it is working fine. Please help me on sorting this issue.
If you add
[Install]
WantedBy=multi-user.target
I think it will work ;)
I found solution for the above problem. I modified my service in the following way. It works fine after the modification.
[Unit]
Description=/etc/rc.d/rc.local Compatibility
ConditionFileIsExecutable=/etc/rc.d/rc.local
After=network.target
[Service]
Type=forking
ExecStart=/etc/rc.d/rc.local start
ControlGroup=cpu:/
SysVStartPriority=99

Resources