systemd: getty-like service for htop

  • Tutorial

htop is an interactive process monitoring program; she is an alternative to the top program. Everyone who works behind a Linux machine on board has used it at least once: whether it was searching for a process (and its subsequent killing) or carefully monitoring the resources used.



For convenience, this program can be kept always running: in a separate terminal window, in its tabs or on some desktop. But there is another solution: run it on a fixed VT, which you can switch to at any time. The advantage of this approach is a clean environment and independence from X / terminal.


It is possible (and correct) to do this using the initialization system, because we actually want to get a special getty-like service for htop.


How do VT1, ..., VT6 start?


agetty- this is such a program that opens the tty port, issues a prompt for authentication and transfers subsequent control to another program - login.


$ which agetty login | xargs ls -l
-rwxr-xr-x 1 root root 44104 Sep 29 05:21 /usr/bin/agetty
-rwxr-xr-x 1 root root 35968 Sep 29 05:21 /usr/bin/login

Traditional Linux initialization systems are configured to run a fixed amount agettyat boot time. In most cases, six instances are created for six VTs: from tty1 to tty6, respectively. Systemd takes a different approach.


  • The first is dynamic . The service instance is getty@.servicelaunched on demand. That is, only if we need a specific VT. Logind is responsible for this, which when switching to ttyN starts a service autovt@ttyN.servicethat is symlinked to getty@.service. This logic works for tty2-tty6.
  • The second is static . A specific service instance getty@.serviceis automatically retracted through getty.target, which gives us always running getty on tty1.

systemctl cat getty@.servicewill show the contents of this service. We are not going to consider it in detail, since this is not so important for us.


Accordingly, if we assume that we have one htop@.service, then we can add it to the autoload in two ways: either make a symlink under the name autovt@ttyN.service- then when switching to the selected VT, htop will start instead of getty, or disable getty@ttyN.serviceand enable it instead htop@ttyN.service- this always gives us running htop on a fixed VT.


Writing our own getty-like unit


Now go to /etc/systemd/system- one of the directories where the units are located - and create our own service:


$ "$EDITOR" htop@.service

The presence of the suffix ( @) means that the service does not start by itself, but one of its instances. A suffix parammetrom passed into it ( %iand %I).


It was already noted above that the content getty@.serviceis not so important for us. That's right, because it can be included in our service:


.include /usr/lib/systemd/system/getty@.service

Given that our service is getty-like, this construction saves us from unnecessary code copying.


Unit Section


It describes the general parameters applicable to any type of unit.


[Unit]
Description=htop on %I
Documentation=man:htop(1)

Everything is transparent here: the directive Descriptionsets a short description of the unit, and the Documentationpath to the documentation. %IIs the name of the instance. It is important to note that both variables specifying the instance name are different in meaning: %I- the same as %i, but it does not escape escape sequences.


Service Section


This section configures the service specifically. In other words, describes how to start the process.


[Service]
Environment=
Environment=TERM=linux HOME=/root
ExecStart=
ExecStart=/usr/bin/htop
StandardInput=tty-fail
StandardOutput=tty

We will leave the necessary inherited values ​​of the directives alone, and we need to reset some (set an empty value for them) and define them ourselves. These include Environment- setting variables, and ExecStart, - actually, starting the process.


StandardInput=tty-fail
StandardOutput=tty

- This is an indication of systemd to start htop connected directly to the terminal.


By the way, you can add not an instant start, but with the expectation of input. To do this, create a simple script on the bash:


#!/bin/bash
echo "Press a key to launch $(basename "$1")"
read
exec "$@"

All he does is wait for input and run some kind of program (which will be htop in our case). We place it anywhere, call it whatever you like, make it executable ( chmod +x) and edit ExecStartin our service:


ExecStart=/etc/systemd/scripts/run_wait /usr/bin/htop

Limit Rights


If you need to impose any restrictions on the rights, then of course you need to do this. To do this, we will create another service and another script, and now - htop_secure@.serviceand run_wait_su. We reconfigure them so that htop starts with the rights of a specific user and a specific group, and also requires an administrator password.


So, we create a new service and a new script based on the two previous ones:


$ cd /etc/systemd
$ cp system/htop@.service system/htop_secure@.service
$ cp scripts/run_wait scripts/run_wait_su

And we edit each of them. For the service in the Service section, change the value of Environment and set the username with its group:


User=kalterfive
Group=users
Environment=TERM=linux

And in the script, we turn to su(1):


#!/bin/bash
echo "Press a key to launch $(basename "$1")"
read
exec su -c "$@"

Service Installation


Now our service is ready, it remains only to add it to startup:


$ systemctl daemon-reload
$ systemctl disable getty@tty2.service
$ systemctl enable htop@tty2.service

The first command updates the systemd configuration manager, and the second creates a symlink to our service in getty.target.wants.


Conclusion


Now we reboot (or manually kill getty@and turn it on htop@for the tty2 instance), switch to the second VT and observe the successfully launched htop. The demonstrated trick affects only a small part of systemd, as an initialization system, from the full scope of its capabilities, as a universal plumbing layer — a set of programs for solving completely different problems. Good luck!



Also popular now: