What is needed for a minimal systemd boot to launch getty on a virtual console?
Solution 1
First of all, systemd
is not a traditional unix init
. Systemd is so much more, so it's a bit unfair to compare the two.
To answer the question, what appears to be necessary are some binaries and the following configuration files:
/usr/lib/systemd/system/default.target /usr/lib/systemd/system/basic.target /usr/lib/systemd/system/sysinit.target /usr/lib/systemd/system/getty.target /usr/lib/systemd/system/[email protected] /usr/lib/systemd/system/console-getty.service
issuing systemctl enable console-getty.service [email protected]
then creates these symlinks:
/etc/systemd/system/default.target.wants/[email protected] -> /lib/systemd/system/getty@service /etc/systemd/system/getty.target.wants/console-getty.service -> /lib/systemd/system/console-getty.service
NOTE: To utilize systemd
's special features for starting agetty
dynamically, on-demand when pressing Alt+F3 and so on, it appears that you must also have at least these two files:
/etc/systemd/logind.conf /lib/systemd/system/[email protected]
where [email protected]
is a symlink to [email protected]
.
Contents of configuration files:
The default.target
, getty.target
, sysinit.target
files can be empty except for the [Unit]
tag and (probably) Description=xxx
.
basic.target
also contains dependency information:
[Unit] Description=Basic System Requires=sysinit.target Wants=sockets.target timers.target paths.target slices.target After=sysinit.target sockets.target timers.target paths.target slices.target
I'm not sure if the references to targets that don't exist as files are needed or not. They are described on the systemd.special(7)
man page.
console-getty.service
: (Special case for agetty on the console)
[Unit] Description=Console Getty After=systemd-user-sessions.service plymouth-quit-wait.service Before=getty.target [Service] ExecStart=-/sbin/agetty --noclear --keep-baud console 115200,38400,9600 $TERM Type=idle Restart=always RestartSec=0 UtmpIdentifier=cons TTYPath=/dev/console TTYReset=yes TTYVHangup=yes KillMode=process IgnoreSIGPIPE=no SendSIGHUP=yes [Install] WantedBy=getty.target
[email protected]
: (generic config for all getty services except console)
[Unit] Description=Getty on %I After=systemd-user-sessions.service plymouth-quit-wait.service Before=getty.target IgnoreOnIsolate=yes ConditionPathExists=/dev/tty0 [Service] ExecStart=-/sbin/agetty --noclear %I $TERM Type=idle Restart=always RestartSec=0 UtmpIdentifier=%I TTYPath=/dev/%I TTYReset=yes TTYVHangup=yes TTYVTDisallocate=no KillMode=process IgnoreSIGPIPE=no SendSIGHUP=yes [Install] WantedBy=getty.target DefaultInstance=tty1
Finally you probably need a few of these special binaries (I haven't tried which ones are crucial):
/lib/systemd/systemd (/sbin/init usually points to this) /lib/systemd/systemd-logind /lib/systemd/systemd-cgroups-agent /lib/systemd/systemd-user-sessions /lib/systemd/systemd-vconsole-setup /lib/systemd/systemd-update-utmp /lib/systemd/systemd-sleep /lib/systemd/systemd-sysctl /lib/systemd/systemd-initctl /lib/systemd/systemd-reply-password /lib/systemd/systemd-ac-power /lib/systemd/systemd-activate /lib/systemd/systemd-backlight /lib/systemd/systemd-binfmt /lib/systemd/systemd-bootchart /lib/systemd/systemd-bus-proxyd /lib/systemd/systemd-coredump /lib/systemd/systemd-cryptsetup /lib/systemd/systemd-fsck /lib/systemd/systemd-hostnamed /lib/systemd/systemd-journald /lib/systemd/systemd-journal-gatewayd /lib/systemd/systemd-journal-remote /lib/systemd/systemd-localed /lib/systemd/systemd-machined /lib/systemd/systemd-modules-load /lib/systemd/systemd-multi-seat-x /lib/systemd/systemd-networkd /lib/systemd/systemd-networkd-wait-online /lib/systemd/systemd-quotacheck /lib/systemd/systemd-random-seed /lib/systemd/systemd-readahead /lib/systemd/systemd-remount-fs /lib/systemd/systemd-resolved /lib/systemd/systemd-rfkill /lib/systemd/systemd-shutdown /lib/systemd/systemd-shutdownd /lib/systemd/systemd-socket-proxyd /lib/systemd/systemd-timedated /lib/systemd/systemd-timesyncd /lib/systemd/systemd-udevd /lib/systemd/systemd-update-done
To summarize the systemd start process, I think it works something like this:
- systemd locates
basic.target
(or all*.target
files?) - dependencies are resolved based on
WantedBy=
,Wants=
,Before=
,After=
... directives in the[Install]
section of the*.service
and*.target
configuration files. -
*.service
s that should start (that are not "special" services), have a[Service]
section with aExecStart=
directive, that points out the executable to start.
Solution 2
systemd
automatically creates a getty when you switch to the terminals, up to a certain maximum number. The default is 6 (so you get automatically a getty for alt+f1 to alt+f6). If you want to change this parameter you can edit /etc/systemd/logind.conf
to change NAutoVTs
parameter to some other number (max 12)
If you want a getty to spawn even if you don't manually switch you can add a symlink to /usr/lib/systemd/system/[email protected]
to the /etc/systemd/system/getty.target.wants/
directory:
ln -sf /usr/lib/systemd/system/[email protected] /etc/systemd/system/getty.target.wants/[email protected]
this will result in the getty.target
requiring one more getty@
service.
A target is a collection of services that need to be spawned, replacement of runlevels which supports dependencies. The default target depends on getty.target
See at systemd FAQ in ArchWiki
edit: I researched a bit more in the documentation.
At boot the systemd
daemon loads all systems in the default
target and their dependencies. A target is defined by the files
/etc/systemd/system/default.target
/usr/lib/systemd/system/default.target
A target has a list of attached services specified by symlinks in the directories
/etc/systemd/system/default.target.wants
/usr/lib/systemd/system/default.target.wants
The /etc
version overrides the distribution defaults in /usr/lib
. Only one of the .target
files is required, while none of the directory is required
getty
is just one of the services among others which can be run by init scripts. In the distribution I checked (fedora, arch) getty
is run in two different ways:
- Started by specific scripts for each terminal (links to the
/usr/lib/systemd/system/[email protected]
file in which the tty name is substituted in bysystemd
from the link filename) - Automatically brought up as needed by the
logind
when the user switch to a virtual terminal (similar to the way oldinetd
brought up services only when a request arrives).logind
is a different daemon distributed withsystemd
, and reads its configuration from the/etc/systemd/logind.conf
file.
Hope this is satisfying.
Solution 3
After some experiments I found that one target-service pair is enough to boot into. Copied from emergency.service
:
[Unit]
DefaultDependencies=no
Description=shell.service: Console and Login
[Service]
Environment=HOME=/root
WorkingDirectory=-/root
ExecStart=-/usr/lib/systemd/systemd-sulogin-shell
ExecStartPost=/usr/bin/openvt -f -c 16 agetty tty16
ExecStartPost=/usr/bin/openvt -f -c 17 -- agetty -p tty17
ExecStartPost=/usr/bin/openvt -f -c 18 -- agetty -p -a USER tty18
Type=idle
StandardInput=tty-force
StandardOutput=inherit
StandardError=inherit
#KillMode=process
KillMode=control-group
IgnoreSIGPIPE=no
SendSIGHUP=yes
For testing: renaming the distro's unit dir to /lib/systemd/systemDEACT
is a simple but radical way to reduce the number of units/unit-files from 200 to 10; there are still some false ones:
UNIT LOAD ACTIVE SUB DESCRIPTION
dev-sda3.device loaded activating tentative /dev/sda3
-.mount loaded active mounted Root Mount
tmp.mount loaded active mounted /tmp
init.scope loaded active running System and Service Manager
io.service loaded inactive dead io: usbhid kmod for keyboard
remount.service loaded inactive dead remount: rw for / and tmpfs for /tmp
shell.service loaded active running shell.service: Console and Login
-.slice loaded active active Root Slice
system.slice loaded active active System Slice
* systemd-journald.socket not-found inactive dead systemd-journald.socket
* local-fs-pre.target not-found inactive dead local-fs-pre.target
* local-fs.target not-found inactive dead local-fs.target
mini.target loaded active active "mini": Minimal Boot and Shell
* swap.target not-found inactive dead swap.target
* umount.target not-found inactive dead umount.target
Beside shell.service
(see top) I made a remount.service
and io.service
; the modprobe usbhid
is crucial for my (any?) USB keyboard. The remount service needs a sync with the fsck in arch's initrd script for the remount and with tmp.mount for /tmp
. I also have to find out where to place that rw
correctly on the KCL...in the meantime I get a couple of green [OK]
at bootup from two oneshot and one idle services.
The dependency tree is:
mini.target
* |-io.service
* |-remount.service
* `-shell.service
With my remount
redundant/conflicting with KCL and io
just doing modprobe usbhid
(which can be done with a ExecStart...
in shell.service
also), this is just one target/service pair. Plus the default.target
link if you don't add systemd.unit=mini.target
on the kernel CL.
I spent hours chasing the tentative dev-sdaX.device
(the only, root partition); now I think this is halfways normal.
-.mount
and -.slice
and init.scope
are internal and make sense.
tmp.mount
I think is generated in /run
.
The not-found
journald, local-fs, swap and umount units don't seem to hurt systemd; with --state loaded
they are not shown. They probably should be created as first additional units. But how define local-fs
when root partition comes already checked from initrd? Can a boot with initrd be minimal?
systemctl status
is also minimal. There is a slice, but only one (no user-X slices):
* archlinux
State: running
Jobs: 0 queued
Failed: 0 units
Since: Fri 2021-10-01 15:24:16 UTC; 3min 2s ago
CGroup: /
|-init.scope
| `-1 /sbin/init arch\x5cvmlinuz-linux
`-system.slice
`-shell.service
|-215 /usr/lib/systemd/systemd-sulogin-shell
|-219 bash
|-220 agetty tty16
|-222 agetty -p tty17
|-225 agetty -p -a USER tty18
`-238 systemctl status
With KillMode
you can control what happens to the processes inside shell.service. The corresponding ps axf
is:
1 ? Ss 0:00 /sbin/init arch\vmlinuz-linux
215 tty1 Ss 0:00 /usr/lib/systemd/systemd-sulogin-shell
219 tty1 S 0:00 \_ bash
245 tty1 R+ 0:00 \_ ps axf
246 tty1 S+ 0:00 \_ tail -8
220 tty16 Ss+ 0:00 agetty tty16
222 tty17 Ss+ 0:00 agetty -p tty17
225 tty18 Ss+ 0:00 agetty -p -a USER tty18
The agetty
s have no parent - thanks to openvt
? - but still PID1/init/systemd keeps track of the pids. I was able to restart shell.service
with different KillMode
s.
A ctrl-D
or exit
on that sulogin-shell is not recommended...
And how can I stop all this?
After that radical dir-rename the reboot
command "can not talk to init daemon" or so. A (copy of) reboot.service
with action reboot-force
(not reboot, not reboot-immediate) is the most direct way out, and sufficient for this test bootup (no journald running etc.). Sysvinit shutdown is not really elegant either, nor fast. systemctl start reboot
then does the PID signalling and killing and a sync
(I guess), but no otherwise ordered shutdown. That would be with a "final" or "shutdown" target, from where you can go to CPU reboot
, poweroff
or halt
. With or w/o shutdown-initramfs.
So systemd
can start and run (and stop!) without journald, udevd and dbus and all these unit files, and --user
instances. But it is hard to "supermask" (i.e. make go away) the 200 distro-units, and then there still are some traces of built-in units and built-in logic.
TL;DR: emergency.target
, DefaultDependencies=no
, openvt
Related videos on Youtube
MattBianco
Updated on September 18, 2022Comments
-
MattBianco over 1 year
For SysV
init
, I need/etc/inittab
respawning getty entries, the/sbin/init
binary, the binaries and shared libraries for the shell,login
, thegetty
, the PAM/security/shadow stuff, and a few device files.For
upstart
I need pretty much the same requirements, but instead of/etc/inittab
, I have a few*.conf
files under/etc/init
: one *.conf thatstart on startup
that sets a runlevel withtelinit
, and one *.conf for each tty that start/respawngetty
on that tty on the appropriate runlevels.What configuration and binaries do I need for
systemd
init
?The documentation I find all seems to be focused on how to use an already-installed system to start and stop services.
A minimal list of files to copy (except the kernel/initrd) from a running Arch or fedora installation would do fine, but I cannot seem to find that kind of information about
systemd
.
What I would like to know is, for
systemd
, what files are required, and what must they contain, to start a login shell after an initramfs does it'sswitch_root
call to thesystemd
/sbin/init
.
Example for
upstart
, the binaries and two*.conf
files:File
/etc/init/whatever.conf
:start on startup emits runlevel task script telinit 2 end script
File
/etc/init/tty1.conf
:start on runlevel [12345] respawn exec /sbin/agetty -8 --noclear 38400 tty1 linux
Example for
sysvinit
, the binaries and 1 conf file named/etc/inittab
:id:2:initdefault: c1:12345:respawn:/sbin/agetty 38400 tty1 linux
Now I'm after the
systemd
equivalent.I assume at least 1
*.service
file is needed somewhere, with a[Service]
entry containingExecStart=-/sbin/agetty --noclear %I linux
andRestart=always
, but what else is needed?-
MattBianco over 9 yearsNow there is a recent RedHat knowledge base article (754933) describing the systemd boot at this URL: Overview of systemd for RHEL 7
-
ceving almost 7 yearsIt is so depressingly to see how people blow up a single configuration line into a big mess and call it improvement.
-
-
MattBianco over 9 yearsI want to know which files are needed, and what they shall contain. Could you summarize your answer with a list of files that are required and what causes them to be read in what order? I'm missing info about what needs to be found in that directory. I'll try to elaborate my question a bit. Thanks!
-
MattBianco over 9 yearsYes, I'm spoiled by documentation from other open source projects. I'm sorry for sounding hostile. It's just frustrating that there seems to be no simple document explaining the boot process. (I understand now that it is because systemd is not simple.) In a humorous way I'd like to comment that it is perhaps
systemd
that is hostile, as in performing a hostile takeover of the way an open system starts. It turns GNU/Linux away from Unix. Not saying that that's a bad thing, but it is very different from how things have traditionally been. And googling around a bit indicates that I'm not alone. -
Stefan Majewsky over 9 yearsAFAIK the
[Install]
section is not used by the boot sequence, only bysystemctl enable
. What the boot looks at is the symlinks in/etc/systemd/system/basic.target.wants/
, which are created bysystemctl enable
.