The other day I answered a question on running htop on a virtual terminal on the SLE forums, which got me thinking about how can systemd handle this.
So how do the current vt’s get created? Via the systemd service getty@.service and the amount set via /etc/systemd/systemd-logind.conf which by default is 6, I normally only use two (which was modified via the now defunct /etc/inittab).
Sure it only saves a few bytes of RAM…but hey I can then use it elsewhere…
So I modified the entry to NAutoVTs=2 now only ALT+CTL+F1 or F2 will fire up a vt (aka tty)
Creating the service file was just basically a copy of the getty one with some tweaks, like adding the command of course along with some default htop options;
[Unit]
Description=Process view on a Virtual Terminal with htop.
[Service]
Type=simple
Environment=TERM=linux
TTYPath=/dev/tty12
ExecStart=/bin/sh -c "/usr/bin/htop d 1 P > /dev/tty12 < /dev/tty12"
ExecStop=/bin/sh -c "/usr/bin/clear > /dev/tty12 < /dev/tty12"
Restart=always
RestartSec=0
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
KillSignal=SIGHUP
[Install]
Alias=htop.target.wants/htop.service
This will work from the getgo, however it’s running as root, this allows any user to control the system, so we don’t want that…
So the first hurdle, get access to tty12 on the fly since only root can access;
Hello udev (and udevadm) So I need to create a rule that will allow a user to access a tty;
udevadm info --query=all --name=tty12 --attribute-walk
Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.
looking at device '/devices/virtual/tty/tty12':
KERNEL=="tty12"
SUBSYSTEM=="tty"
DRIVER==""
So I can build a rule based on the above along with a username and adding the user to the tty group;
KERNEL=="tty12", SUBSYSTEM=="tty", NAME="%k", OWNER="username", GROUP="tty" MODE="0660"
I saved this as /etc/udev/rules.d/10-tty.rules so it gets called early by udev.
Now, to get the systemd service to run based on the username, we add a new variable to the service;
[Service]
.....
User=username
.....
Now I can get the service running as my user, which is fine on a single user system, what we really need is a limited user just running the htop application, then it should be fairly secure. And what about additional htop options?
So lets create a htopd user for this service with no login shell, but part of the system users as well;
useradd -r -o -g tty -u 200 -s /bin/false -c "systemd htop user" -d /var/lib/htopd htopd
This will create a system user (-r) belonging to the tty group (-g) along with a /bin/false shell, comment and a home directory that useradd will be happy with.
There doesn’t seem to be a list on openSUSE or the reserved system UID’s so I just picked 200…
So the 10-tty.rules file needs to be updated with the OWNER being htopd.
Now what if I don’t want to use tty12 say I want to use 11 on the fly, udev supports some regex feature so I can modify the KERNEL option to KERNEL==“tty[1]*” so it will work from tty11 - tty19.
You need to research how to use different keys for the Fn > 12 as you can have up to 255 vt’s if you want with different left-right etc key presses.
So the final 10-tty.rules file is;
KERNEL=="tty[1]*", SUBSYSTEM=="tty", NAME="%k", OWNER="htopd", GROUP="tty" MODE="0660"
Now how to pass these options to the systemd service, just like init scripts sourced a config file systemd does it the same with the Environment variable which you may have noticed in the original service code above Environment=TERM=linux. And along with a configuration file in /etc/sysconfig we can add options via YaST for the service on the fly.
First the sysconfig file with htop options and ability to select either tty11 or tty12;
## Path: System/htop
## Description: htop systemd service parameters
## Type: string
## Default: "d 1 P"
## ServiceRestart: systemctl restart htop.service
#
# Parameters for htop, default delay 1 second and sort by %cpu,
# see the htop man page for more options.
#
HTOP_PARAMS="d 1 P"
## Type: list(11,12)
## Default: "12"
#
# /dev/ttyN is used for the htop service as determined by
# by /etc/udev/rules.d/10-tty.rules.
#
HTOP_TTY="12"
So there is a sysconfig file so that we can add/change the htop options and I made it tty selection a ‘list’ with only 11 and 12.
So now some additional magic with the service file to add the environment options and we should be good to go;
[Unit]
Description=Process view on a Virtual Terminal with htop.
[Service]
Type=simple
EnvironmentFile=-/etc/sysconfig/htop
Environment=TERM=linux
User=htopd
TTYPath=/dev/tty${HTOP_TTY}
ExecStart=/bin/sh -c "/usr/bin/htop ${HTOP_PARAMS} > /dev/tty${HTOP_TTY} < /dev/tty${HTOP_TTY}"
ExecStop=/bin/sh -c "/usr/bin/clear > /dev/tty${HTOP_TTY} < /dev/tty${HTOP_TTY}"
Restart=always
RestartSec=0
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
KillSignal=SIGHUP
[Install]
Alias=htop.target.wants/htop.service
So we can source our config file via the EnvironmentFile option, then pass these options with a ${} wrapper, not too bad at all.
The other options automatically restart the htop service if you press quit etc and there is only the htopd user running htop so it’s the only process that you can kill, except it restarts…
I added a clear command, just so the screen would be blanked after the service is stopped.
So remember, ALT+CTRL+F12 to open the tty and ALT+CTRL+F7(or 8) to get back to your desktop.
Arise systemd-htop-service;
htop running on tty12
The package is available here;
software.opensuse.org: Search Results