systemd unit file to run bash command with terminal input - systemd

I have the following unit file:
[Unit]
Description=Startup Thing
[Service]
Type=simple
ExecStart=/bin/bash
StandardInput=tty
TTYPath=/dev/pts/19
What I am trying to do is pipe input from a terminal to /bin/bash. But for some reason the terminal kind of doesn't process my input correctly. When I type "ls", the terminal only shows the "l" and no "s"... this happens to all other commands as well. What am I doing wrong?

Related

Getting the exit code of an application launched via startx

I'm setting up Debian so that it works in kiosk mode. To do this, I created a service that performs the watchdog function:
[Unit]
Description=Watchdog for Myapp
After=getty#tty6.service
After=polkit.service
After=udisks2.service
[Service]
ExecStart=su user -c "startx /opt/myapp -- :0 vt5"
ExecStop=systemctl start xdm
Type=simple
Restart=on-failure
StartLimitInterval=60s
StartLimitBurst=5
RuntimeMaxSec=infinity
Environment="DISPLAY=:0"
Environment="XAUTHORITY=/home/user/.Xauthority"
Environment="XDG_VTNR=5"
[Install]
WantedBy=graphical.target
The problem is that ExecStart gets the exit code not from myapp, but from startx. I have tried many options, but I have not been able to come up with a way that would work as it should...
I tried trying to pass exit code through pipe, exit &? and writing the exit code to a file. But, apparently, my skills in bash are not enough to make the right command.
Googling also didn't help because to find a case in which people call starts directly from the root, and not from the user, which is why the transfer of exit code is much easier than in my case

systemd not capturing echo statement from shell script

I have a systemd service file which is directly calling a shell script. My expectation is that stdout and stderr from the file would be captured by journal+console, but it is only appearing in syslog. What should I change in my service file or the script file such that it behaves as expected?
The service file looks like:
[Unit]
Description=Test
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
Restart=always
RestartSec=5min
TimeoutSec=5min
GuessMainPID=no
ExecStart=/tmp/script start systemd
ExecStop=/tmp/script stop systemd
SuccessExitStatus=143
User=test
Group=test
LimitAS=infinity
LimitRSS=infinity
LimitNPROC=4096
LimitNOFILE=65536
StandardOutput=journal+console
[Install]
WantedBy=multi-user.target graphical.target
The script actually invokes a jar but to simplify let's consider a simpler version:
#!/bin/sh
echo "ERROR: Java not found"
exit 1
Using systemd-cat and logger I was able to direct echo statement to systlog and journald, still the log did not show up on the console.
What is the correct way to direct stdout and stderr to journal+console?

How to run a specific program before systemd's watchdog stops a service

I have a program which is run by systemd with a service file like this:
[Unit]
Description=...
[Service]
Type=notify
ExecStart=/usr/sbin/myprogram
WatchdogSec=1
KillMode=process
KillSignal=SIGTERM
Restart=always
It sends the respective signal to the watchdog regularly. From time to time, the program seems to hang and is terminated by the watchdog, then restarts. Before the watchdog terminates it, I'd like to capture some information from the program by executing a command or running some other script (e.g. run gdb -p <PID> --batch -ex 'thread apply all backtrace'). How would I do this?
Add a ExecStop= to your service.
[Service]
ExecStart=....
ExecStop=/path/to/SomeOtherProgram
....
According to systemd manual, if ExecStop option is available, it will run that first, then if the process under ExecStart is still available after this, it will run the KillMode.
ExecStop=
Commands to execute to stop the service started via
ExecStart=. This argument takes multiple command lines, following the
same scheme as described for ExecStart= above. Use of this setting is
optional. After the commands configured in this option are run, it is
implied that the service is stopped, and any processes remaining for
it are terminated according to the KillMode= setting (see
systemd.kill(5)). If this option is not specified, the process is
terminated by sending the signal specified in KillSignal= when service
stop is requested. Specifier and environment variable substitution is
supported (including $MAINPID, see above).
EDIT
As in the comment below, this solution may not work for Watchdog option in the service file.

Embedded linux application start script works better from command line

I'm running embedded linux on an Altera FPGA. It uses SystemD to run startup, and I have a script in the "multi-user.target.wants" section that runs my application.
When it runs from startup my code runs slower than when I run the identical script from an ssh shell.
I have checked that paths are the same, that permissions are correct on the scripts, that full paths are used in the scripts. Using 'top' I can see that priorities are set the same for the various threads started, yet somehow performance is completely different between the two ways of starting.
The script in full is:
#!/bin/sh
sleep 5s
mount /dev/mmcblk0p5 /home/root/linux
cd /home/root/linux/mem_driver
./memdev_load
cd /home/root/linux/gpio_driver
insmod ./gpiodev.ko
mknod /dev/gpiodev c 249 0
sleep 5s
cd /home/root/src/control
mysqld_safe &
up=0
while [ $up -ne 2 ]
do
up=$(pgrep mysql | wc -l);
echo $up
done
sleep 3s
cd /home/root/studio_web/myapp
npm start &
sleep 1s
cd /home/root/src/control
#sleep 1s
./control > /home/root/linux/output.log
various sleep commands have been inserted to try and make sure things start up in the right order.
Any help in diagnosing why this behaves differently would be greatly appreciated.
Is that the only shell script you are using? or do you have a systemd service file that executes that single shell script?
Using sleep is ineffective here. You should separate them into separate shell scripts and then use systemd to ensure that the shell scripts are run in order.
For example, we want to mount the directory first, because if this fails then nothing following will be successful. So we create a systemd mount service:
# home-root-linux.mount
[Unit]
Description=Mount /home/root/linux
Before=gpiodev.service
[Mount]
What=/dev/mmcblk0p5
Where=/home/root/linux
Options=defaults
[Install]
WantedBy=multi-user.target
Then we can create another systemd service which depends on the mount above before executing the three parts of the shell script which were previously separated by sleep to ensure that they were run in order.
# gpiodev.service
[Unit]
Description=Handle gpiodev kernel module
After=home-root-linux.mount
Before=mysqlsafe.service
[Service]
Type=oneshot
ExecStartPre=/home/root/linux/mem_driver/memdev_load
ExecStart=/sbin/insmod gpiodev.ko; /bin/mknod /dev/gpiodev c 249 0
WorkingDirectory=/home/root/linux/gpio_driver
RemainAfterExit=yes
StandardOutput=journal
[Install]
WantedBy=multi-user.target
Second part of the systemd service (following the sleep). We have a separate shellscript which is placed in /sbin/ in this example as it contains a while loop so it would be best to separate this:
# mysqlsafe.service
[Unit]
Description=MySQL safe
After=gpiodev.service
Before=npmoutput.service
[Service]
Type=oneshot
ExecStart=/sbin/mysqlsafe.sh
WorkingDirectory=/home/root/src/control
RemainAfterExit=yes
StandardOutput=journal
[Install]
WantedBy=multi-user.target
Second part of the shell script which is executed in the systemd service above (separated to a separate file due to the complexity):
# /sbin/mysqlsafe.sh
#!/bin/sh
mysqld_safe &
up=0
while [ $up -ne 2 ]
do
up=$(pgrep mysql | wc -l);
echo $up
done
Third part of the systemd service (the third section of the original shell script which was separated by sleep):
# mpmoutput.service
[Unit]
Description=npm and output to log
After=mysqlsafe.service
[Service]
Type=oneshot
ExecStartPre=/usr/bin/npm &
ExecStart=/home/root/src/control > /home/root/linux/output.log
WorkingDirectory=/home/root/studio_web/myapp
RemainAfterExit=yes
StandardOutput=journal
[Install]
WantedBy=multi-user.target
The idea behind this approach is that systemd recognises the importance of each service and the reliance upon the following service i.e. if one service fails the following services in queue will not execute. You can then check this using systemctl and see logging in journalctl.
Just a quick copy, paste and edit. Could contain errors as it was not tested or checked.
More reading can be found here regarding systemd service files: https://www.freedesktop.org/software/systemd/man/systemd.service.html

How to redirect log file content to systemd journal?

I have a program that accept a --log-file parameter. I want to wrapper this program into a systemd service, and write the log to the journal.
The program can run in daemon mode, and supports restart and stop actions.
I found a systemd-cat, but it only accept a pipe.
Try using the bash feature of process substitution.
myapp --log-file >(systemd-cat)
Put following command in ExecStart of service unit file
myapp --log-file /dev/stdout
Building off Mark Stosberg suggestion. What worked for me was to use process substitution with bash.
ExecStart=/bin/bash -c '/location/app --log >(systemd-cat)'

Resources