SYSTEMD-ANALYZE(1)
๐ SYSTEMD-ANALYZE(1) ๐
okay bestie, so this is the manpage for systemd-analyze โ yes, that's the manual name, and yes, it's giving main character energy for your whole boot process. she analyzes, she debugs, she tells you why your system is being slow. let's go โจ
๐ธ NAME ๐ธ
systemd-analyze โ Analyze and debug system manager
๐ SYNOPSIS ๐
systemd-analyze [OPTIONS...] [time]
systemd-analyze [OPTIONS...] blame
systemd-analyze [OPTIONS...] critical-chain [UNIT...]
systemd-analyze [OPTIONS...] dump [PATTERN...]
systemd-analyze [OPTIONS...] plot [>file.svg]
systemd-analyze [OPTIONS...] dot [PATTERN...] [>file.dot]
systemd-analyze [OPTIONS...] unit-files
systemd-analyze [OPTIONS...] unit-gdb SERVICE
systemd-analyze [OPTIONS...] unit-paths
systemd-analyze [OPTIONS...] unit-shell SERVICE [COMMAND...]
systemd-analyze [OPTIONS...] exit-status [STATUS...]
systemd-analyze [OPTIONS...] capability [CAPABILITY... |
{-m | --mask} MASK]
systemd-analyze [OPTIONS...] condition CONDITION...
systemd-analyze [OPTIONS...] syscall-filter [SET...]
systemd-analyze [OPTIONS...] filesystems [SET...]
systemd-analyze [OPTIONS...] calendar SPEC...
systemd-analyze [OPTIONS...] timestamp TIMESTAMP...
systemd-analyze [OPTIONS...] timespan SPAN...
systemd-analyze [OPTIONS...] cat-config NAME|PATH...
systemd-analyze [OPTIONS...] compare-versions VERSION1 [OP] VERSION2
systemd-analyze [OPTIONS...] verify FILE...
systemd-analyze [OPTIONS...] security [UNIT...]
systemd-analyze [OPTIONS...] inspect-elf FILE...
systemd-analyze [OPTIONS...] malloc [D-BUS SERVICE...]
systemd-analyze [OPTIONS...] fdstore UNIT...
systemd-analyze [OPTIONS...] image-policy POLICY...
systemd-analyze [OPTIONS...] has-tpm2
systemd-analyze [OPTIONS...] identify-tpm2
systemd-analyze [OPTIONS...] pcrs [PCR...]
systemd-analyze [OPTIONS...] nvpcrs [NVPCR...]
systemd-analyze [OPTIONS...] srk [>FILE]
systemd-analyze [OPTIONS...] architectures [NAME...]
systemd-analyze [OPTIONS...] smbios11
systemd-analyze [OPTIONS...] chid
systemd-analyze [OPTIONS...] transient-settings TYPE...
โจ DESCRIPTION โจ
so like. systemd-analyze is your bestie for figuring out how long your system took to boot up, grabbing other state and tracing info from the system and the service manager, and checking that your unit files are actually correct. she also unlocks some special functions that are very useful for advanced system manager debugging. iykyk ๐
and if you pass no command at all? it just implies systemd-analyze time. no thoughts, just time. periodt.
โฑ๏ธ systemd-analyze time โฑ๏ธ
this one prints three things: how much time got spent in the kernel before userspace was even reached, how much time got spent in the initrd before the normal system userspace was reached, and how long the normal system userspace took to initialize. ๐ซถ
heads up bestie โ these measurements are just measuring the time up to the point where all system services have been spawned. that's NOT necessarily the same as them fully finishing initialization or the disk being idle. so don't come for her if the number looks cute and the system is still grinding ๐
okay so if the manager carried shutdown timestamps across a kexec-based live update (i.e. they were restored from the previous boot through the Live Update Orchestrator), then the previous boot's shutdown phases get prepended to the chain. so you see the whole shutdown plus bootup sequence, and it all gets summed into the total: the time spent stopping units ("(stopping)"), the time the manager took to hand off to systemd-shutdown(8) ("(exit)"), and the time spent in systemd-shutdown itself ("(systemd-shutdown)") all get added before the firmware/loader/kernel/initrd/userspace phases. the way that stack just keeps growing ๐ญ
Example 1. Show how long the boot took
# in a container
$ systemd-analyze time
Startup finished in 296ms (userspace)
multi-user.target reached after 275ms in userspace
# on a real machine
$ systemd-analyze time
Startup finished in 2.584s (kernel) + 19.176s (initrd) + 47.847s (userspace) = 1min 9.608s
multi-user.target reached after 47.820s in userspace
๐ซฃ systemd-analyze blame ๐ซฃ
this command prints a list of all running units, sorted by how long they took to initialize. use it to optimize your boot-up times, bestie. she's basically a leaderboard for slow services ๐
but ngl, the output might be misleading, because one service's initialization might be slow simply because it's waiting for another service to finish initializing. also note: systemd-analyze blame does not display results for services with Type=simple, because systemd considers those services to be started immediately โ so no measurement of the initialization delays can even be done. ๐
and another thing: this command only shows the time units took for starting up, it does NOT show how long unit jobs spent in the execution queue. specifically, it shows the time units spent in the "activating" state, which isn't even defined for units like device units that transition directly from "inactive" to "active". so this command gives you a vibe check on the performance of program code, but it can't accurately reflect latency introduced by waiting for hardware and similar events. fr fr.
Example 2. Show which units took the most time during boot
$ systemd-analyze blame
32.875s pmlogger.service
20.905s systemd-networkd-wait-online.service
13.299s dev-vda1.device
...
23ms sysroot.mount
11ms initrd-udevadm-cleanup-db.service
3ms sys-kernel-config.mount
๐ณ systemd-analyze critical-chain [UNIT...] ๐ณ
this one prints a tree of the time-critical chain of units (for each of the UNITs you specify, or for the default target if you don't specify any). the time after the unit is active or started gets printed after the "@" character. the time the unit takes to start gets printed after the "+" character. iconic formatting tbh.
but like, the output might be misleading, because the initialization of services might depend on socket activation and because of the parallel execution of units. also, same asblame, this only takes into account the time units spent in"activating"state, so it doesn't cover units that never went through an"activating"state (like device units that transition directly from"inactive"to"active"). and on top of that, it doesn't show info on jobs โ and in particular not jobs that timed out. ๐ญ
Example 3. systemd-analyze critical-chain
$ systemd-analyze critical-chain
multi-user.target @47.820s
โโpmie.service @35.968s +548ms
โโpmcd.service @33.715s +2.247s
โโnetwork-online.target @33.712s
โโsystemd-networkd-wait-online.service @12.804s +20.905s
โโsystemd-networkd.service @11.109s +1.690s
โโsystemd-udevd.service @9.201s +1.904s
โโsystemd-tmpfiles-setup-dev.service @7.306s +1.776s
โโkmod-static-nodes.service @6.976s +177ms
โโsystemd-journald.socket
โโsystem.slice
โโ-.slice
๐ systemd-analyze dump [pattern...] ๐
no parameters? then this command outputs a (usually very long) human-readable serialization of the complete service manager state. you can optionally pass a glob pattern, which limits the output to units whose names match one of the patterns. ๐ฆ
โ ๏ธ the output format is subject to change without notice and should not be parsed by applications. also, this command is rate limited for unprivileged users. so no scripting against it, bestie, i'm serious.
Example 4. Show the internal state of user manager
$ systemd-analyze --user dump
Timestamp userspace: Thu 2019-03-14 23:28:07 CET
Timestamp finish: Thu 2019-03-14 23:28:07 CET
Timestamp generators-start: Thu 2019-03-14 23:28:07 CET
Timestamp generators-finish: Thu 2019-03-14 23:28:07 CET
Timestamp units-load-start: Thu 2019-03-14 23:28:07 CET
Timestamp units-load-finish: Thu 2019-03-14 23:28:07 CET
-> Unit proc-timer_list.mount:
Description: /proc/timer_list
...
-> Unit default.target:
Description: Main user target
...
๐ง systemd-analyze malloc [D-Bus service...] ๐ง
this command requests the output of the internal memory state (as returned by malloc_info(3)) of a D-Bus service. if you don't specify a service, the query goes to org.freedesktop.systemd1 (that's the system or user service manager).
the output format is not guaranteed to be stable and should not be parsed by applications. nope nope nope.
the service must implement the org.freedesktop.MemoryAllocation1 interface. in the systemd suite, it's currently only implemented by the manager. so like, it's exclusive ๐
๐ systemd-analyze plot ๐
this command prints either an SVG graphic detailing which system services have been started at what time (highlighting the time they spent on initialization), OR the raw time data in JSON or table format. choose your fighter โจ
Example 5. Plot a bootchart
$ systemd-analyze plot >bootup.svg
$ eog bootup.svg&
note that this plot is based on the most recent per-unit timing data of loaded units. which means: if a unit gets started, then stopped, then started again, the info shown covers the most recent start cycle, not the first one. so it's recommended to consult this info only shortly after boot, so that this distinction doesn't matter. ๐
and also โ units that aren't referenced by any other unit through a dependency might get unloaded by the service manager once they terminate (and didn't fail). those units will not show up in the plot. rip to them, they're not invited ๐ซถ
๐ธ๏ธ systemd-analyze dot [pattern...] ๐ธ๏ธ
this command generates a textual dependency graph description in dot format for further processing with the GraphViz dot(1) tool. use a command line like systemd-analyze dot | dot -Tsvg >systemd.svg to generate a graphical dependency tree. unless --order or --require is passed, the generated graph will show both ordering and requirement dependencies. you can give optional pattern globbing style specifications (e.g. *.target) at the end. a unit dependency is included in the graph if any of these patterns match either the origin or the destination node. obsessed with how flexible this is ๐
Example 6. Plot all dependencies of any unit whose name starts with "avahi-daemon"
$ systemd-analyze dot 'avahi-daemon.*' | dot -Tsvg >avahi.svg
$ eog avahi.svg
Example 7. Plot the dependencies between all known target units
$ systemd-analyze dot --to-pattern='*.target' --from-pattern='*.target' \
| dot -Tsvg >targets.svg
$ eog targets.svg
๐ systemd-analyze unit-paths ๐
this command outputs a list of all the directories from which unit files, .d overrides, and .wants, .requires symlinks may be loaded. combine it with --user to retrieve the list for the user manager instance, and --global for the global configuration of user manager instances. ๐
Example 8. Show all paths for generated units
$ systemd-analyze unit-paths | grep '^/run'
/run/systemd/system.control
/run/systemd/transient
/run/systemd/generator.early
/run/systemd/system
/run/systemd/system.attached
/run/systemd/generator
/run/systemd/generator.late
and that's part 1 bestie!! there's SO much more coming, don't go anywhere ๐
Note that this verb prints the list that's compiled into systemd-analyze itself โ it does not talk to the running manager at all, bestie. If you want the list your manager is actually working with, run this instead:
systemctl [--user] [--global] show -p UnitPath --value
...and any empty directories just get dropped from it. ๐
systemd-analyze exit-status [STATUS...]
This one hands you a list of exit statuses, each with its "class" โ as in, where that definition came from (it's one of "libc", "systemd", "LSB", or "BSD"). Full deets live in the Process Exit Codes section of systemd.exec(5). Pass no extra arguments and it dumps every known status. Pass some, and you only get the definitions for the codes you asked about. โจ
Example 9. Show some example exit status names
$ systemd-analyze exit-status 0 1 {63..65}
NAME STATUS CLASS
SUCCESS 0 libc
FAILURE 1 libc
- 63 -
USAGE 64 BSD
DATAERR 65 BSD
systemd-analyze capability [CAPABILITY... | {-m | --mask} MASK]
Linux capabilities, plus their numeric IDs, served up fresh. See capabilities(7) if you want the lore. No argument? You get the whole list of capabilities known to the service manager and the kernel. Anything the kernel defines but the service manager has never heard of shows up as "cap_???" โ iconically mysterious. ๐
Optionally you can pass arguments naming specific capabilities by name or numeric ID, and then only those show up in the table.
OR โ and this is the fun part โ if you pass --mask, you must give exactly one numeric argument, which gets read as a hexadecimal capability mask. Then only the capabilities present in that mask appear. This mode exists to help you decode capability sets you pull out of debugging interfaces like /proc/PID/status. ๐ต๏ธ
Example 10. Show some example capability names
$ systemd-analyze capability 0 1 {30..32}
NAME NUMBER
cap_chown 0
cap_dac_override 1
cap_audit_control 30
cap_setfcap 31
cap_mac_override 32
Example 11. Decode a capability mask extracted from /proc
$ systemd-analyze capability -m 0000000000003c00
NAME NUMBER
cap_net_bind_service 10
cap_net_broadcast 11
cap_net_admin 12
cap_net_raw 13
systemd-analyze condition CONDITION...
Feed it Condition*=... and Assert*=... assignments and it will evaluate them, print their values, and then tell you the resulting value of the whole combined condition set. The full menu of conditions and asserts lives in systemd.unit(5). ๐
Example 12. Evaluate conditions that check kernel versions
$ systemd-analyze condition 'ConditionVersion = ! <4.0' \
'ConditionVersion = >=5.1' \
'ConditionACPower=|false' \
'ConditionArchitecture=|!arm' \
'AssertPathExists=/etc/os-release'
test.service: AssertPathExists=/etc/os-release succeeded.
Asserts succeeded.
test.service: ConditionArchitecture=|!arm succeeded.
test.service: ConditionACPower=|false failed.
test.service: ConditionVersion=>=5.1 succeeded.
test.service: ConditionVersion=!<4.0 succeeded.
Conditions succeeded.
systemd-analyze syscall-filter [SET...]
Lists the system calls sitting inside the system call set SET you name โ or every known set, if you name none. Heads up: SET must include the "@" prefix, no exceptions. ๐
systemd-analyze filesystems [SET...]
Same energy, different table: lists the filesystems in the filesystem set SET you name, or all known sets if you name none. And yep โ SET must include the "@" prefix. โจ
systemd-analyze calendar EXPRESSION...
Parses and normalizes repetitive calendar time events, then works out when they elapse next. It takes exactly the same input as the OnCalendar= setting in systemd.timer(5), using the syntax from systemd.time(7). By default you just get the next elapse time โ but hit it with --iterations= and you'll get however many upcoming elapse times you asked for. Each time the expression elapses forms a timestamp, and there's a timestamp verb for those (scroll down, bestie). ๐ฆ
Example 13. Show leap days in the near future
$ systemd-analyze calendar --iterations=5 '*-2-29 0:0:0'
Original form: *-2-29 0:0:0
Normalized form: *-02-29 00:00:00
Next elapse: Sat 2020-02-29 00:00:00 UTC
From now: 11 months 15 days left
Iter. #2: Thu 2024-02-29 00:00:00 UTC
From now: 4 years 11 months left
Iter. #3: Tue 2028-02-29 00:00:00 UTC
From now: 8 years 11 months left
Iter. #4: Sun 2032-02-29 00:00:00 UTC
From now: 12 years 11 months left
Iter. #5: Fri 2036-02-29 00:00:00 UTC
From now: 16 years 11 months left
systemd-analyze timestamp TIMESTAMP...
Parses a timestamp โ one single point in time, not a span โ and spits out the normalized form plus the difference between it and now. Your timestamp needs to follow the syntax in systemd.time(7), section "PARSING TIMESTAMPS". ๐ธ
Example 14. Show parsing of timestamps
$ systemd-analyze timestamp yesterday now tomorrow
Original form: yesterday
Normalized form: Mon 2019-05-20 00:00:00 CEST
(in UTC): Sun 2019-05-19 22:00:00 UTC
UNIX seconds: @15583032000
From now: 1 day 9h ago
Original form: now
Normalized form: Tue 2019-05-21 09:48:39 CEST
(in UTC): Tue 2019-05-21 07:48:39 UTC
UNIX seconds: @1558424919.659757
From now: 43us ago
Original form: tomorrow
Normalized form: Wed 2019-05-22 00:00:00 CEST
(in UTC): Tue 2019-05-21 22:00:00 UTC
UNIX seconds: @15584760000
From now: 14h left
systemd-analyze timespan EXPRESSION...
Now for spans โ the difference between two timestamps. It parses it, prints the normalized form, and gives you the equivalent value in microseconds. The syntax you need is in systemd.time(7), section "PARSING TIME SPANS". Oh and btw: any value you give without units gets parsed as seconds. ๐
Example 15. Show parsing of timespans
$ systemd-analyze timespan 1s 300s '1year 0.000001s'
Original: 1s
ฮผs: 1000000
Human: 1s
Original: 300s
ฮผs: 300000000
Human: 5min
Original: 1year 0.000001s
ฮผs: 31557600000001
Human: 1y 1us
systemd-analyze cat-config NAME|PATH...
Basically systemctl cat but for config files, and honestly? Iconic. It copies the contents of a config file and any drop-ins to standard output, using the usual systemd directories and the usual precedence rules. Every argument has to be either an absolute path that includes the prefix (like /etc/systemd/logind.conf or /usr/lib/systemd/logind.conf), or a name relative to the prefix (like systemd/logind.conf). ๐
Example 16. Showing logind configuration
$ systemd-analyze cat-config systemd/logind.conf
# /etc/systemd/logind.conf
...
[Login]
NAutoVTs=8
...
# /usr/lib/systemd/logind.conf.d/20-test.conf
... some override from another package
# /etc/systemd/logind.conf.d/50-override.conf
... some administrator override
systemd-analyze compare-versions VERSION1 [OP] VERSION2
Two whole modes of operation here, depending on whether you pass the operator OP. ๐ฅ
Mode one โ no OP: it compares the two version strings and prints whichever fits: "VERSION1 < VERSION2", "VERSION1 == VERSION2", or "VERSION1 > VERSION2".
The exit status is 0 if the versions are equal, 11 if the version on the right is smaller, and 12 if the version on the left is smaller. (Yes, that matches the convention rpmdev-vercmp uses. ๐)
Mode two โ OP given: it compares the two version strings using the operation OP and returns 0 (success) if the condition is satisfied, and 1 (failure) otherwise. OP may be lt, le, eq, ne, ge, gt. In this mode, nothing gets printed. (And that matches the convention dpkg(1) --compare-versions uses.)
Example 17. Compare versions of a package
$ systemd-analyze compare-versions systemd-250~rc1.fc36.aarch64 systemd-251.fc36.aarch64
systemd-250~rc1.fc36.aarch64 < systemd-251.fc36.aarch64
$ echo $?
12
$ systemd-analyze compare-versions 1 lt 2; echo $?
0
$ systemd-analyze compare-versions 1 ge 2; echo $?
1
systemd-analyze verify FILE...
Loads unit files and prints warnings if it detects any errors. Files you name on the command line get loaded โ but so does anything else they reference. You can override a unit's name on disk by specifying an alias after a colon (there's an example below, keep reading ๐). The full unit search path is built by combining the directories of all the command line arguments with the usual unit load paths. The variable $SYSTEMD_UNIT_PATH is supported and can replace or augment the compiled-in set of unit load paths โ see systemd.unit(5). Any unit files sitting in the directories that hold your command line arguments get used in preference to the other paths. And if you hand it a template unit with no instance name (like foo@.service), "test_instance" will be used as the instance name โ you can steer that with the --instance= option. ๐
Here's what it currently detects:
- unknown sections and directives,
- missing dependencies that are required to start the given unit,
- man pages listed in
Documentation=that aren't found on the system, - commands listed in
ExecStart=and similar that aren't found on the system, or aren't executable.
Example 18. Misspelt directives
$ cat ./user.slice
[Unit]
WhatIsThis=11
Documentation=man:nosuchfile(1)
Requires=different.service
[Service]
Description=x
$ systemd-analyze verify ./user.slice
[./user.slice:9] Unknown lvalue 'WhatIsThis' in section 'Unit'
[./user.slice:13] Unknown section 'Service'. Ignoring.
Error: org.freedesktop.systemd1.LoadFailed:
Unit different.service failed to load:
No such file or directory.
Failed to create user.slice/start: Invalid argument
user.slice: man nosuchfile(1) command failed with code 16
Example 19. Missing service units
$ tail ./a.socket ./b.socket
==> ./a.socket <==
[Socket]
ListenStream=100
==> ./b.socket <==
[Socket]
ListenStream=100
Accept=yes
๐ Example 20. Aliasing a unit ๐
ok so picture this: you got a file that's just vibing with no proper name. bestie, watch what happens ๐
$ cat /tmp/source
[Unit]
Description=Hostname printer
[Service]
Type=simple
ExecStart=/usr/bin/echo %H
MysteryKey=true
$ systemd-analyze verify /tmp/source
Failed to prepare filename /tmp/source: Invalid argument
๐ญ it literally refuses. it's giving "who even are you". BUT โ give it a name and it'll finally talk to you:
$ systemd-analyze verify /tmp/source:alias.service
alias.service:7: Unknown key name 'MysteryKey' in section 'Service', ignoring.
see?? the alias let it get all the way to line 7 and THEN it clocked the fake key. iconic behaviour honestly ๐
๐ systemd-analyze security [UNIT...] ๐
okay so this one is the security check-up bestie, and it's lowkey my fave.
So: this command analyzes the security and sandboxing settings of one or more specified service units. If at least one unit name is specified, the security settings of the specified service units are inspected and a detailed analysis is shown. If no unit name is specified, all currently loaded, long-running service units are inspected and a terse table with results is shown.
Then it does the thing โจ: the command checks for various security-related service settings, assigning each a numeric "exposure level" value, depending on how important a setting is. It then calculates an overall exposure level for the whole unit โ which is an estimation in the range 0.0...10.0 showing how exposed a service is security-wise.
- High exposure levels = very little applied sandboxing ๐จ
- Low exposure levels = tight sandboxing and strongest security restrictions ๐ซถ
โ ๏ธ big caveat time: this only analyzes the per-service security features systemd itself implements. That means any additional security mechanisms applied by the service code itself are not accounted for.
And do NOT misread the number, bestie. The exposure level determined this way should not be misunderstood: a high exposure level neither means that there is no effective sandboxing applied by the service code itself, nor that the service is actually vulnerable to remote or local attacks. High exposure levels do indicate however that most likely the service might benefit from additional settings applied to them.
Also please note โ and this is the part nobody reads and everyone should ๐ โ that many of the security and sandboxing settings individually can be circumvented unless combined with others. For example, if a service retains the privilege to establish or undo mount points, many of the sandboxing options can be undone by the service code itself. Because of that it is essential that each service uses the most comprehensive and strict sandboxing and security settings possible. The tool will take into account some of these combinations and relationships between the settings, but not all.
And one more: also note that the security and sandboxing settings analyzed here only apply to the operations executed by the service code itself. If a service has access to an IPC system (such as D-Bus) it might request operations from other services that are not subject to the same restrictions. So any comprehensive security and sandboxing analysis is hence incomplete if the IPC access policy is not validated too. no cap ๐
๐ Example 21. Analyze systemd-logind.service ๐
$ systemd-analyze security --no-pager systemd-logind.service
NAME DESCRIPTION EXPOSURE
โ PrivateNetwork= Service has access to the host's network 0.5
โ User=/DynamicUser= Service runs as root user 0.4
โ DeviceAllow= Service has no device ACL 0.2
โ IPAddressDeny= Service blocks all IP address ranges
...
โ Overall exposure level for systemd-logind.service: 4.1 OK ๐
the โ's are the lil side-eyes and the โ is the lil gold star โญ and honestly 4.1 OK is such a mood.
๐ง systemd-analyze inspect-elf FILE... ๐ง
This command will load the specified files, and if they are ELF objects (executables, libraries, core files, etc.) it will parse the embedded packaging metadata, if any, and print it in a table or json format. See the Package Metadata for Executable Files[1] document for more information.
๐ธ Example 22. Print information about a core file as JSON ๐ธ
$ systemd-analyze inspect-elf --json=pretty \
core.fsverity.1000.f77dac5dc161402aa44e15b7dd9dcf97.58561.1637106137000000
{
"elfType" : "coredump",
"elfArchitecture" : "AMD x86-64",
"/home/bluca/git/fsverity-utils/fsverity" : {
"type" : "deb",
"name" : "fsverity-utils",
"version" : "1.3-1",
"buildId" : "7c895ecd2a271f93e96268f479fdc3c64a2ec4ee"
},
"/home/bluca/git/fsverity-utils/libfsverity.so.0" : {
"type" : "deb",
"name" : "fsverity-utils",
"version" : "1.3-1",
"buildId" : "b5e428254abf14237b0ae70ed85fffbb98a78f88"
}
}
pretty json my beloved ๐ (don't forget that backslash-newline continuation in the command, it's load-bearing!)
๐ฆ systemd-analyze dlopen-metadata FILE ๐ฆ
This command will load the specified file, and if it is an ELF object (executables, libraries, core files, etc.) it will parse the embedded dlopen metadata, if any, and print it in a table or json format. See the dlopen() Metadata for ELF Files[2] document for more information.
(it's the sibling of inspect-elf, same energy, different metadata โจ)
๐ systemd-analyze fdstore UNIT... ๐
Lists the current contents of the specified service unit's file descriptor store. This shows names, inode types, device numbers, inode numbers, paths and open modes of the open file descriptors.
The specified units must have FileDescriptorStoreMax= enabled, see systemd.service(5) for details.
๐ Example 23. Table output ๐
$ systemd-analyze fdstore systemd-journald.service
FDNAME TYPE DEVNO INODE RDEVNO PATH FLAGS
stored sock 0:8 4218620 - socket:[4218620] ro
stored sock 0:8 4213198 - socket:[4213198] ro
stored sock 0:8 4213190 - socket:[4213190] ro
...
๐ Note: the"DEVNO"column refers to the major/minor numbers of the device node backing the file system the file descriptor's inode is on. The"RDEVNO"column refers to the major/minor numbers of the device node itself if the file descriptor refers to one. Compare with corresponding.st_devand.st_rdevfields instruct stat(seestat(2)for details). The listed inode numbers in the"INODE"column are on the file system indicated by"DEVNO".
๐ systemd-analyze image-policy POLICY... ๐
This command analyzes the specified image policy string, as per systemd.image-policy(7). The policy is normalized and simplified. For each currently defined partition identifier (as per the UAPI.2 Discoverable Partitions Specification[3]) the effect of the image policy string is shown in tabular form.
๐ Example 24. Example Output ๐
$ systemd-analyze image-policy swap=encrypted:usr=read-only-on+verity:root=encrypted
Analyzing policy: root=encrypted:usr=verity+read-only-on:swap=encrypted
Long form: root=encrypted:usr=verity+read-only-on:swap=encrypted:=unused+absent
PARTITION MODE READ-ONLY GROWFS
root encrypted - -
usr verity yes -
home ignore - -
srv ignore - -
esp ignore - -
xbootldr ignore - -
swap encrypted - -
root-verity ignore - -
usr-verity unprotected yes -
root-verity-sig ignore - -
usr-verity-sig ignore - -
tmp ignore - -
var ignore - -
default ignore - -
look at it go โ it even normalized your input and showed you the long form. main character energy fr โจ
๐ฅ systemd-analyze has-tpm2 ๐ฅ
Reports whether the system is equipped with a usable TPM2 device.
- If a TPM2 device has been discovered, is supported, and is being used by firmware, by the OS kernel drivers and by userspace (i.e. systemd) โ this prints
"yes"and exits with exit status zero โ - If no such device is discovered/supported/used โ prints
"no" - Otherwise โ prints
"partial"
In either of these two cases it exits with non-zero exit status.
It also shows five lines indicating separately whether firmware, drivers, the system, the kernel and libraries discovered/support/use TPM2. Currently, required libraries are libtss2-esys.so.0, libtss2-rc.so.0, and libtss2-mu.so.0. The requirement may be changed in the future release.
๐ Note: this checks for TPM 2.0 devices only, and does not consider TPM 1.2 at all. sorry 1.2 girlies.
Combine with --quiet to suppress the output. ๐คซ
๐ Example 25. Example Output ๐
yes
+firmware
+driver
+system
+subsystem
+libraries
+libtss2-esys.so.0
+libtss2-rc.so.0
+libtss2-mu.so.0
Added in version 257.
โญ systemd-analyze identify-tpm2 โญ
Shows vendor information about the TPM 2.0 device discovered. ๐
๐ง Example 26. Example Output ๐ง
Family Indicator: 2.0
Level: 0
Revision: 1.59
Specification Date: Mon 2023-01-09
Manufacturer: STM
Vendor String: ST33KTPM2XSPI
Firmware Version: 9.258
Modalias String: fi2.0:lv0:rv1.59:sy2023:sd9:mfSTM:vsST33KTPM2XSPI:ty0:fw9.258.0:
Added in version 260.
๐ systemd-analyze pcrs [PCR...] ๐
This command shows the known TPM2 PCRs along with their identifying names and current values.
๐ธ Example 27. Example Output ๐ธ
$ systemd-analyze pcrs
NR NAME SHA256
0 platform-code bcd2eb527108bbb1f5528409bcbe310aa9b74f687854cc5857605993f3d9eb11
1 platform-config b60622856eb7ce52637b80f30a520e6e87c347daa679f3335f4f1a600681bb01
2 external-code 1471262403e9a62f9c392941300b4807fbdb6f0bfdd50abfab752732087017dd
3 external-config 3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969
4 boot-loader-code 939f7fa1458e1f7ce968874d908e524fc0debf890383d355e4ce347b7b78a95c
5 boot-loader-config 864c61c5ea5ecbdb6951e6cb6d9c1f4b4eac79772f7fe13b8bece569d83d3768
6 - 3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969
7 secure-boot-policy 9c905bd9b9891bfb889b90a54c4b537b889cfa817c4389cc25754823a9443255
8 - 0000000000000000000000000000000000000000000000000000000000000000
9 kernel-initrd 9caa29b128113ef42aa53d421f03437be57211e5ebafc0fa8b5d4514ee37ff0c
10 ima 5ea9e3dab53eb6b483b6ec9e3b2c712bea66bca1b155637841216e0094387400
11 kernel-boot 0000000000000000000000000000000000000000000000000000000000000000
12 kernel-config 627ffa4b405e911902fe1f1a8b0164693b31acab04f805f15bccfe2209c7eace
13 sysexts 0000000000000000000000000000000000000000000000000000000000000000
14 shim-policy 0000000000000000000000000000000000000000000000000000000000000000
15 system-identity 0000000000000000000000000000000000000000000000000000000000000000
16 debug 0000000000000000000000000000000000000000000000000000000000000000
17 - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
18 - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
19 - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
20 - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
21 - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
22 - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
23 application-support 0000000000000000000000000000000000000000000000000000000000000000
systemd-analyze nvpcrs [NVPCR...]</p>
okay so this one pulls up the known TPM2 NvPCRs โ those are the extra PCRs that live in TPM2 NV indexes โ and shows you their identifying names plus whatever values they're holding right now. โจ
Example 28. Example Output
$ systemd-analyze nvpcrs
NAME NVINDEX VALUE
cryptsetup 0x1d10201 f400543943cc7215557ce672872ace5382e6d53177cc459078ba9277e41588d9
hardware 0x1d10200 e155474936d7d74c893e6ece1099a2311d572cf23becea159dabf282db754284
Added in version 259.
systemd-analyze srk [>FILE]</p>
this reads the Storage Root Key (SRK) straight off the TPM2 device and writes it to stdout in marshalled TPM2B_PUBLIC format ๐
heads up bestie, the output is non-printable data, so you gotta redirect it into a file or a pipe โ do not just stare at your terminal wondering why it's glitching.
Example 29. Save the Storage Root Key to srk.tpm2b_public
systemd-analyze srk >srk.tpm2b_public
systemd-analyze architectures [NAME...]</p>
this one lists every known CPU architecture and tells you which ones are native. the architecture names it spits out are exactly the ones ConditionArchitecture= supports, peep systemd.unit(5) for the deets. and if you pass architecture names, it only lists the ones you asked for. no cap. ๐
Example 30. Table output
$ systemd-analyze architectures
NAME SUPPORT
alpha foreign
arc foreign
arc-be foreign
arm foreign
arm64 foreign
...
sparc foreign
sparc64 foreign
tilegx foreign
x86 secondary
x86-64 native
systemd-analyze smbios11</p>
shows you the list of SMBIOS Type #11 strings that got passed to the system. also go look at smbios-type-11(7) if you want the lore. ๐ฆ
Example 31. Example output
$ systemd-analyze smbios11
io.systemd.stub.kernel-cmdline-extra=console=ttyS0
io.systemd.credential.binary:ssh.ephemeral-authorized_keys-all=c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSURGd20xbFp4WlRGclJteG9ZQlozOTYzcE1uYlJCaDMwM1MxVXhLSUM2NmYgbGVubmFydEB6ZXRhCg==
io.systemd.credential:vmm.notify_socket=vsock-stream:2:254570042
3 SMBIOS Type #11 strings passed.
Added in version 257.
systemd-analyze chid</p>
this shows the Computer Hardware IDs (CHIDs) of the local system ๐ซถ these IDs are what identify your system's computer hardware, and they're based on SMBIOS data. if you wanna go deep, see Using Computer Hardware IDs (CHIDs)[4]. ๐
Example 32. Example output
$ systemd-analyze chid
TYPE INPUT CHID
3 MFPSmp 520537c0-3b59-504f-b062-9682ea236b21
4 MFPS-- edf05dc8-a53d-5b2c-8023-630bca2a2463
5 MFP--- ebc6a4d9-ec48-537a-916b-c69fa4fdd814
6 M--Smp 5ebe4bba-f598-5e90-9ff2-9fd0d3211465
7 M--S-- 1a3fb835-b42a-5f9c-a38c-eff5bfd5c41d
8 M-P-mp 2a831dce-8163-5bad-8406-435b8c752dd8
9 M-P--- 7c21c878-4a75-50f7-9816-21e811588da0
10 MF--mp 9a003537-bcc5-500e-b10a-8d8892e4fc64
11 MF---- bb9122bb-8a5c-50d2-a742-a85beb719909
13 M---mp bfc36935-5032-5987-a0a3-6311f01de33a
LEGEND: M โ sys_vendor (LENOVO) โ F โ product_family (ThinkPad X1 Carbon Gen 9) โ P โ product_name (20XW0055GE)
S โ product_sku (LENOVO_MT_20XW_BU_Think_FM_ThinkPad X1 Carbon Gen 9) โ m โ board_vendor (LENOVO)
p โ board_name (20XW0055GE)
Added in version 258.
systemd-analyze transient-settings TYPE...</p>
okay so this lists all the properties you can set for various unit types through command line interfaces โ specifically systemctl(1) set-property and the --property=/--automount-property= options in systemd-run(1), systemd-nspawn(1), and systemd-mount(1). those assignments only work for a subset of the properties you can set in config files, so also check systemd.unit(5), systemd.exec(5), systemd.resource-control(5), and all the other unit-type-specific pages. the TYPE argument has to be a unit type ("service", "socket", ...) and it lists the properties that apply to those specific types. ๐
Note: the D-Bus properties documented in org.freedesktop.systemd1(5) form a partially overlapping set with the lists this command generates. lots of D-Bus properties and transient settings share the same names, BUT for example LogRateLimitIntervalSec= is described in systemd.exec(5) and would be listed by this command, while the corresponding D-Bus property described in systemd.exec(5) is LogRateLimitIntervalUSec. not the same, bestie, do not get it twisted ๐ญ
this verb is intended primarily for programmatic generation of shell completions.
Added in version 258.
systemd-analyze unit-shell SERVICE [command...]</p>
the given command runs inside the namespace of the specified running service. and if you don't give a command? it just spawns a shell attached to the service's namespace. main character energy tbh. โจ
Example 33. Example output
$ systemd-analyze unit-shell systemd-resolved.service ls
bin dev etc home lib lib64 lost+found mnt proc run srv tmp var vmlinuz.old
boot efi exitrd init lib32 libx32 media opt root sbin sys usr vmlinuz work
Added in version 258.
systemd-analyze unit-gdb SERVICE</p>
spawns a debugger and attaches it to the given service ๐ฅ by default it uses gdb(1), but you can swap that out with the --debugger= option or the $SYSTEMD_DEBUGGER environment variable. and if you wanna pass extra command line arguments to the debugger, use --debugger-arguments= โ and please quote them properly when ARGS contain whitespace (see the Example, it's giving "I learned this the hard way"). ๐
Example 34.
$ systemd-analyze --debugger-arguments="-batch -ex 'info all-registers'" unit-gdb systemd-oomd.service
Added in version 258.
โจ OPTIONS โจ
these are the options that are understood, bestie, collect them all ๐
--systemโ operates on the system systemd instance. this is the implied default. Added in version 209.--userโ operates on the user systemd instance. Added in version 186.--globalโ operates on the system-wide configuration for user systemd instance. Added in version 238.--order,--requireโ when used alongside thedotcommand (see above), this picks which dependencies show up in the dependency graph. pass--orderand only dependencies of typeAfter=orBefore=are shown. pass--requireand only dependencies of typeRequires=,Requisite=,BindsTo=,Wants=, andConflicts=are shown. pass neither and you get dependencies of all these types. Added in version 198.--from-pattern=,--to-pattern=โ when used alongside thedotcommand (see above), this selects which relationships show up in the dependency graph. both options need aglob(7)pattern as an argument, which gets matched against the left-hand and the right-hand nodes of a relationship respectively. ๐
each of these can be used more than once, and in that case the unit name must match one of the values. when tests for both sides of the relation are present, a relation must pass both tests to be shown. when patterns are also specified as positional arguments, they must match at least one side of the relation. in other words: patterns given with those two options trim the list of edges matched by the positional arguments (if any are given), and otherwise they fully determine the list of edges shown. Added in version 201.
--fuzz=timespanโ when used alongside thecritical-chaincommand (see above), it also shows units that finished timespan earlier than the latest unit in the same level. the unit of timespan is seconds unless you specify a different unit, e.g."50ms". Added in version 203.--man=noโ don't invokeman(1)to verify that the man pages listed inDocumentation=actually exist. Added in version 235.--generatorsโ invoke unit generators, seesystemd.generator(7). some generators need root privileges, so heads up: running this as a normal user with generators enabled will generally result in some warnings. ๐ Added in version 235.--instance=NAMEโ specifies the fallback instance name for template units. it gets used when one or more template units without an instance name (e.g.foo@.service) are specified forsystemd-analyze conditionwith--unit=,systemd-analyze security, andsystemd-analyze verify. if you leave it unspecified,"test_instance"is used. Added in version 257.--recursive-errors=MODEโ okay so this one controls howsystemd-analyze verifychecks units and their dependencies, and whether it bails out with a non-zero exit status or just vibes. Withyes, you get a non-zero process exit status when warnings pop up during verification of either the unit you named or any of its associated dependencies. Withno, non-zero exit status only when warnings come up verifying the specified unit itself. Withone, non-zero exit status when warnings arise verifying either the specified unit or its immediate dependencies. And if you justโฆ don't pass this option at all? Then zero is returned as the exit status regardless of whether warnings arise during verification or not. ๐
Added in version 250.
--root=PATHโ withcat-config,verify,condition,unit-gdb, andsecuritywhen it's used together with--offline=, this makes the tool operate on files underneath the root path you give it inPATH. ๐ซถ
Added in version 239.
--image=PATHโ same squad (cat-config,verify,conditionandsecuritywhen used with--offline=), except this time it operates on files inside the disk image at the pathPATH. ๐ฆ
Added in version 250.
--image-policy=policyโ takes an image policy string as its argument, exactly as described insystemd.image-policy(7). The policy gets enforced when operating on the disk image you passed via--image=, see above. If you don't specify it, it defaults to the"*"policy, meaning all recognized file systems in the image are used. โจ--offline=BOOLโ withsecurity, this does an offline security review of the unit files you specify, i.e. it doesn't have to rely on PID 1 to acquire security info for the files the way the plainsecurityverb does when used by itself. Which means--offline=can be used alongside--root=and--image=too. ๐ Heads up though: if a unit's overall exposure level is above the one set by--threshold=(default value is100),--offline=will return an error.
Added in version 250.
--profile=PATHโ withsecurity --offline=, this takes the specified portable profile into consideration when assessing unit settings. You can pass the profile by name โ in which case the well-known system locations get searched โ or you can hand over the full path to a specific drop-in file. ๐
Added in version 250.
--threshold=NUMBERโ withsecurity, this lets you set a custom value to compare the overall exposure level against, for the unit files you specified. If a unit's overall exposure level is greater than what you set,securitywill return an error.--threshold=works with--offline=as well, and its default value is100. ๐
Added in version 250.
--security-policy=PATHโ withsecurity, this lets you define your own custom set of requirements, formatted as a JSON file, to compare the specified unit file(s) against and determine their overall exposure level to security threats. ๐ฅ
๐ Table 1. Accepted Assessment Test Identifiers
ok so here's the full menu of test IDs you can name-drop, bestie. every single one, in order, no skips ๐
UserOrDynamicUserSupplementaryGroupsPrivateMountsPrivateDevicesPrivateTmpPrivateNetworkPrivateUsersProtectControlGroupsProtectKernelModulesProtectKernelTunablesProtectKernelLogsProtectClockProtectHomeProtectHostnameProtectSystemRootDirectoryOrRootImageLockPersonalityMemoryDenyWriteExecuteNoNewPrivilegesCapabilityBoundingSet_CAP_SYS_ADMINCapabilityBoundingSet_CAP_SET_UID_GID_PCAPCapabilityBoundingSet_CAP_SYS_PTRACECapabilityBoundingSet_CAP_SYS_TIMECapabilityBoundingSet_CAP_NET_ADMINCapabilityBoundingSet_CAP_SYS_RAWIOCapabilityBoundingSet_CAP_SYS_MODULECapabilityBoundingSet_CAP_AUDITCapabilityBoundingSet_CAP_SYSLOGCapabilityBoundingSet_CAP_SYS_NICE_RESOURCECapabilityBoundingSet_CAP_MKNODCapabilityBoundingSet_CAP_CHOWN_FSETID_SETFCAPCapabilityBoundingSet_CAP_DAC_FOWNER_IPC_OWNERCapabilityBoundingSet_CAP_KILLCapabilityBoundingSet_CAP_NET_BIND_SERVICE_BROADCAST_RAWCapabilityBoundingSet_CAP_SYS_BOOTCapabilityBoundingSet_CAP_MACCapabilityBoundingSet_CAP_LINUX_IMMUTABLECapabilityBoundingSet_CAP_IPC_LOCKCapabilityBoundingSet_CAP_SYS_CHROOTCapabilityBoundingSet_CAP_BLOCK_SUSPENDCapabilityBoundingSet_CAP_WAKE_ALARMCapabilityBoundingSet_CAP_LEASECapabilityBoundingSet_CAP_SYS_TTY_CONFIG
quick vibe check โจ โ notice how the first chunk is all the cute lil namey names (PrivateTmp, ProtectHome, etc.) and then the second chunk is the long ones that all start with CapabilityBoundingSet_CAP_. that prefix is literally the whole squad, iykyk ๐ซถ
ngl if you're copy-pasting these, do it character for character โ no auto-correct, no "i'll just fix the caps", no nothing ๐ the shell does not forgive a typo, and these names are case-sensitive fr fr ๐
and that's the whole table, bestie โ every identifier, zero missing, we ate ๐ ๐
...but we are so not done yet, there's still more coming ๐
CapabilityBoundingSet_CAP_BPFUMaskKeyringModeProtectProcProcSubsetNotifyAccessRemoveIPCDelegateRestrictRealtimeRestrictSUIDSGIDRestrictNamespaces_userRestrictNamespaces_mntRestrictNamespaces_ipcRestrictNamespaces_pidRestrictNamespaces_cgroupRestrictNamespaces_utsRestrictNamespaces_netRestrictAddressFamilies_AF_INET_INET6RestrictAddressFamilies_AF_UNIXRestrictAddressFamilies_AF_NETLINKRestrictAddressFamilies_AF_PACKETRestrictAddressFamilies_OTHERSystemCallArchitecturesSystemCallFilter_swapSystemCallFilter_obsoleteSystemCallFilter_clockSystemCallFilter_cpu_emulationSystemCallFilter_debugSystemCallFilter_mountSystemCallFilter_moduleSystemCallFilter_raw_ioSystemCallFilter_rebootSystemCallFilter_privilegedSystemCallFilter_resourcesIPAddressDenyDeviceAllowAmbientCapabilities
Peep the example called "JSON Policy" down below bestie, it's right there ๐
Added in version 250.
--json=MODEโ okay so with thesecuritycommand, this makes a JSON formatted output of the security analysis table. ๐ The format is a JSON array with objects containing these fields:setwhich tells you if the setting has been enabled or not,namewhich is what's used to refer to the setting,json_fieldwhich is the JSON compatible identifier of the setting,descriptionwhich is an outline of the setting state, andexposurewhich is a number in the range0.0...10.0, where a higher value corresponds to a higher security threat. ๐ฅ The JSON version of the table gets printed to standard output. The MODE you pass to the option can be one of three:offwhich is the default,prettyandshortwhich respectively output a prettified or shorted JSON version of the security table. And with theplotcommand, it generates a JSON formatted output of the raw time data. ๐ฆ That format is a JSON array with objects containing these fields:namewhich is the unit name,activatedwhich is the time after startup the service was activated,activatingwhich is how long after startup the service was initially started,timewhich is how long the service took to activate from when it was initially started,deactivatedwhich is the time after startup that the service was deactivated,deactivatingwhich is the time after startup that the service was initially told to deactivate. No cap, that's the whole shape of it โจ
Added in version 250.
--iterations=NUMBERโ when you're rolling with thecalendarcommand, this tells it how many upcoming iterations of that calendar expression to show. default is1. Added in version 242.--base-time=TIMESTAMPโ again with thecalendarcommand, this makes it show the next iterations relative to that specific point in time instead of, like, now. if you don't say anything, it defaults to the current time. โฐ Added in version 244.--unit=UNITโ when you're using theconditioncommand, this evaluates all theCondition*=...andAssert*=...assignments inside the unit file you name. bestie, the full unit search path gets built by combining the directories for that specified unit with the usual unit load paths. the variable$SYSTEMD_UNIT_PATHis supported and you can use it to replace or augment the compiled-in set of unit load paths โ go peepsystemd.unit(5)for that. all unit files sitting in the directory containing the specified unit get used in preference to the other paths. and if you hand it a template unit with no instance name (likefoo@.service), it'll use"test_instance"as the instance name, which you can control with the--instance=option. ๐ Added in version 250.--tableโ when used with theplotcommand, the raw time data gets output as a table. ๐ Added in version 253.--no-legendโ when you use this with theplotcommand together with either--tableor--json=, no legends or hints get included in the output. Added in version 253.-H,--host=โ run the operation remotely. give it a hostname, or a username and hostname separated by"@", to connect to. the hostname can optionally get a port that ssh is listening on tacked on after a":", and then a container name after a"/", which connects you straight to a specific container on that host. this uses SSH to talk to the remote machine manager instance. you can enumerate container names withmachinectl -H HOST. oh and put IPv6 addresses in brackets. ๐ฐ๏ธ-M,--machine=โ run the operation on a local container. name the container you wanna connect to, optionally prefixed by a username to connect as and a separating"@"character. if you use the special string".host"instead of a container name, it makes a connection to the local system (which is super useful when you wanna connect to a specific user's user bus:"--user --machine=lennart@.host"). if you don't use the"@"syntax, the connection is made as the root user. and if you do use the"@"syntax, either the left hand side or the right hand side can be omitted (but not both!) and then the local user name and".host"are implied. ๐-q,--quietโ suppress hints and other non-essential output. Added in version 250.--tldrโ withcat-config, this only prints the "interesting" parts of the config files, skipping comments and empty lines and section headers that are followed only by comments and empty lines. โจ Added in version 255.--scale-svg=FACTORโ when used with theplotcommand, the x-axis of the plot can be stretched by FACTOR (default:1.0). ๐ Added in version 257.--detailedโ when used with theplotcommand, activation timestamps details can be seen in the SVG plot. ๐ Added in version 257.--drm-device=PATHโ when provided with thechidcommand, use this sysfs path to a DRM device to fetch EDID from. example:/sys/class/drm/card1-HDMI-A-1/Added in version 258.--debugger=DEBUGGERโ use the given debugger for theunit-gdbcommand. if you don't give one and$SYSTEMD_DEBUGGERis unset, thengdb(1)gets used. ๐ Added in version 258.- *
-A*ARGS,--debugger-arguments=ARGS โ pass the given ARGS as extra command line arguments to the debugger. Added in version 258. -h,--helpโ print a short help text and exit. ๐ซถ--versionโ print a short version string and exit.--no-pagerโ do not pipe output into a pager.
๐ EXIT STATUS ๐
for most verbs, 0 is returned on success, and a non-zero failure code otherwise. no cap.
for the verb compare-versions, in the two-argument form, 12, 0, or 11 are returned if the second version string is respectively larger than, equal to, or smaller than the first. in the three-argument form, 0 or 1 are returned when the condition is respectively true or false. ๐
for the verb has-tpm2, 0 is returned if a TPM2 device is discovered, supported, and used by firmware, driver, and userspace (i.e. systemd). otherwise, it's the OR combination of the value 1 (in case firmware support is missing), 2 (in case driver support is missing), and 4 (in case userspace support is missing). so if no TPM2 support is available at all, the value 7 is returned. ๐ฅ
โจ ENVIRONMENT โจ
okay bestie, this is the part where you get to โจcustomizeโจ everything without touching a single flag. environment variables, the silent main characters. let's go ๐
$SYSTEMD_LOG_LEVELโ the maximum log level of emitted messages, aka the vibe ceiling. anything with a higher log level (so, less important) gets suppressed. it takes a comma-separated list of values. each value is either one of these, listed in order of decreasing importance:emerg,alert,crit,err,warning,notice,info,debugโ or just an integer in the range0...7. seesyslog(3)for more info. every value can optionally be prefixed with one ofconsole,syslog,kmsgorjournalfollowed by a colon, to set the max log level for that specific log target (like,SYSTEMD_LOG_LEVEL=debug,console:infomeans "log at debug level, except when logging to the console, which should be at info level"). but watch out โ the global max log level takes priority over any per-target max log levels. no cap. ๐$SYSTEMD_LOG_COLORโ a boolean. if true, messages written to the tty get colored according to priority. ๐
this setting is only useful when messages go directly to the terminal, because journalctl(1) and other tools that display logs will color messages based on the log level on their own. they don't need your help bestie.
$SYSTEMD_LOG_TIMEโ a boolean. if true, console log messages get prefixed with a timestamp. โฐ
same deal: only useful when messages are written directly to the terminal or a file, because journalctl(1) and friends attach timestamps based on the entry metadata all by themselves.
$SYSTEMD_LOG_LOCATIONโ a boolean. if true, messages get prefixed with a filename and line number in the source code where the message originates. so you know exactly which line said that. iconic for debugging. ๐
note that the log location is often attached as metadata to journal entries anyway, but putting it right there in the message text can still be convenient when debugging programs.
$SYSTEMD_LOG_TIDโ a boolean. if true, messages get prefixed with the current numerical thread ID (TID).
note that this information is attached as metadata to journal entries anyway. including it directly in the message text can nevertheless be convenient when debugging programs. (yes, the original really does have that little typo in it โ "the this information" โ we're keeping the facts, not the vibes of grammar ๐)
$SYSTEMD_LOG_TARGETโ where your log messages actually go. pick one:consoleโ log to the attached ttyconsole-prefixedโ log to the attached tty, but with prefixes encoding the log level and "facility", seesyslog(3)kmsgโ log to the kernel circular log bufferjournalโ log to the journaljournal-or-kmsgโ log to the journal if available, and tokmsgotherwiseautoโ determine the appropriate log target automatically, this is the defaultnullโ disable log output entirely. silence. ๐ซฅ
$SYSTEMD_LOG_RATELIMIT_KMSGโ whether to ratelimitkmsgor not. takes a boolean. defaults to"true". if disabled, systemd will not ratelimit messages written tokmsg. (so like, prepare for spam ๐)$SYSTEMD_PAGER,$PAGERโ which pager to use when--no-pagerisn't given.$SYSTEMD_PAGERis used if set; otherwise$PAGERis used. if neither$SYSTEMD_PAGERnor$PAGERare set, a set of well-known pager implementations gets tried in turn, includingless(1)andmore(1), until one is found. if no pager implementation is discovered, no pager is invoked at all. setting those environment variables to an empty string or the value"cat"is equivalent to passing--no-pager. ๐ฑ
Note: if$SYSTEMD_PAGERSECUREis not set,$SYSTEMD_PAGERand$PAGERcan only be used to disable the pager (with"cat"or""), and are otherwise ignored. yeah. that's the rule. sorry bestie. ๐
$SYSTEMD_LESSโ override the options passed toless(by default"FRSXMK").
users might want to change two options in particular:
K
this option instructs the pager to exit immediately when Ctrl+C is pressed. to allow less to handle Ctrl+C itself, so it can switch back to the pager command prompt, unset this option.
if the value of $SYSTEMD_LESS does not include "K", and the pager that is invoked is less, Ctrl+C will be ignored by the executable, and needs to be handled by the pager.
X
this option instructs the pager to not send termcap initialization and deinitialization strings to the terminal. it's set by default to allow command output to remain visible in the terminal even after the pager exits. nevertheless, this prevents some pager functionality from working โ in particular, paged output cannot be scrolled with the mouse. ๐ฑ๏ธ๐ซ
note that setting the regular $LESS environment variable has no effect for less invocations by systemd tools.
see less(1) for more discussion.
$SYSTEMD_LESSCHARSETโ override the charset passed toless(by default"utf-8", if the invoking terminal is determined to be UTF-8 compatible). ๐ธ
note that setting the regular $LESSCHARSET environment variable has no effect for less invocations by systemd tools. (systemd only trusts its own prefixed variables, it's giving strict parent energy ๐
)
$SYSTEMD_PAGERSECUREโ okay this one is the serious one, listen up.
common pager commands like less(1), on top of just "paging" (scrolling through the output), also support opening or writing to other files and running arbitrary shell commands. when commands are invoked with elevated privileges โ for example under sudo(8) or pkexec(1) โ the pager becomes a security boundary. care must be taken that only programs with strictly limited functionality are used as pagers, and that unintended interactive features like opening or creating new files, or starting subprocesses, are not allowed. "secure mode" for the pager may be enabled as described below, if the pager supports it (most pagers are not written in a way that takes this into consideration). it is recommended to either explicitly enable "secure mode" or to completely disable the pager using --no-pager or PAGER=cat when allowing untrusted users to execute commands with elevated privileges. ๐ฅ
this option takes a boolean argument. when set to true, the "secure mode" of the pager is enabled. in "secure mode", LESSSECURE=1 will be set when invoking the pager, which instructs the pager to disable commands that open or create new files or start new subprocesses. currently only less(1) is known to understand this variable and implement "secure mode".
when set to false, no limitation is placed on the pager. setting SYSTEMD_PAGERSECURE=0 or not removing it from the inherited environment may allow the user to invoke arbitrary commands. ๐ญ
when $SYSTEMD_PAGERSECURE is not set, systemd tools attempt to automatically figure out if "secure mode" should be enabled and whether the pager supports it. "secure mode" is enabled if the effective UID is not the same as the owner of the login session, see geteuid(2) and sd_pid_get_owner_uid(3), or when running under sudo(8) or similar tools ($SUDO_UID is set [5]). in those cases, SYSTEMD_PAGERSECURE=1 will be set and pagers which are not known to implement "secure mode" will not be used at all. note that this autodetection only covers the most common mechanisms to elevate privileges and is intended as convenience. it is recommended to explicitly set $SYSTEMD_PAGERSECURE or disable the pager. ๐
Note: if the$SYSTEMD_PAGERor$PAGERvariables are to be honoured, other than to disable the pager,$SYSTEMD_PAGERSECUREmust be set too.
$SYSTEMD_COLORSโ takes a boolean argument, or a special value. by default (unset), systemd and related utilities will use colors in their output if possible. if$COLORTERMis set to"truecolor"or"24bit", 24-bit colors will be enabled, 256 colors otherwise โ unless$NO_COLORor$TERMindicates colors are disabled.trueโ same as unset, except that$NO_COLORis ignored.falseโ the output will be monochrome. sad beige terminal. ๐ซฅ"16","256","24bit"โ always use the base 16 ANSI colors, 256 colors, or 24 bit color, respectively."auto-16","auto-256","auto-24bit"โ use the given quantity of colours, subject to$TERM, and what the console is connected to.
$SYSTEMD_URLIFYโ the value must be a boolean. controls whether clickable links should be generated in the output for terminal emulators supporting this. this can be specified to override the decision that systemd makes based on$TERMand other conditions. โจ
โจ EXAMPLES โจ
๐ Example 35. JSON Policy
okay bestie so the JSON file you hand over as a path parameter to --security-policy= is a top-level JSON object, and the keys are literally the assessment test identifiers we were yapping about above. no cap. ๐
And what goes inside those keys? JSON objects, with one or more of these fields:
description_naโ a string, bestiedescription_goodโ also a stringdescription_badโ you guessed it, a stringweightโ an unsigned integerrangeโ an unsigned integer
now here's the tea ๐ซ: if any of these fields for a specific id of the unit file is missing from the JSON object, then the default built-in field value that goes with that same id gets used for the security analysis as the default. so nothing breaks, it just falls back.
weight and range are the ones doing the heavy lifting for figuring out the overall exposure level of the unit files: each setting's value gets assigned a badness score, and that score gets multiplied by the policy weight and divided by the policy range to work out the overall exposure that the setting implies. then all that computed badness gets summed across every setting in the unit file, normalized to the 1...100 range, and that is what determines the overall exposure level of the unit. it's giving math, it's giving main character ๐
and by letting you mess with these fields, the security verb hands you the option to decide for yourself which ids matter more and therefore should hit harder on the exposure level. so iconic of it.
โ ๏ธ heads up: a weight of "0" means that setting will not be checked. periodt.
{
"PrivateDevices":
{
"description_good": "Service has no access to hardware devices",
"description_bad": "Service potentially has access to hardware devices",
"weight": 1000,
"range": 1
},
"PrivateMounts":
{
"description_good": "Service cannot install system mounts",
"description_bad": "Service may install system mounts",
"weight": 1000,
"range": 1
},
"PrivateNetwork":
{
"description_good": "Service has no access to the host's network",
"description_bad": "Service has access to the host's network",
"weight": 2500,
"range": 1
},
"PrivateTmp":
{
"description_good": "Service has no access to other software's temporary files",
"description_bad": "Service has access to other software's temporary files",
"weight": 1000,
"range": 1
},
"PrivateUsers":
{
"description_good": "Service does not have access to other users",
"description_bad": "Service has access to other users",
"weight": 1000,
"range": 1
}
}
๐ SEE ALSO ๐
๐ NOTES ๐
- Package Metadata for Executable Files https://systemd.io/PACKAGE_METADATA_FOR_EXECUTABLE_FILES/
- dlopen() Metadata for ELF Files https://systemd.io/ELF_DLOPEN_METADATA/
- UAPI.2 Discoverable Partitions Specification https://uapi-group.org/specifications/specs/discoverable_partitions_specification
- Using Computer Hardware IDs (CHIDs) https://learn.microsoft.com/en-us/windows-hardware/drivers/dashboard/using-chids
- It is recommended for other tools to set and check
$SUDO_UIDas appropriate, treating it is a common interface.
and that's a wrap, bestie ๐ you just read the whole SYSTEMD-ANALYZE(1) page, from systemd 262.1 โ go forth and analyze your boot, your security, your vibes ๐โจ๐ฆ you ate, no crumbs, fr fr ๐๐
๐ธ
๐ฆ where this page comes from
- arch rolling: systemd 262.1-1 ยท LGPL-2.1-or-later AND CC0-1.0 AND GPL-2.0-or-later AND MIT-0
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms