Inspect systemd Control Groups with systemd-cgls
You will finish with a repeatable way to inspect the processes below a systemd unit, a cgroup path or a container, while keeping the output tied to the scope you actually asked for. The examples were checked with systemd 255, package version 255.4-1ubuntu8.17, on a unified cgroup hierarchy.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about ten minutes. You need a shell and an installed systemd-cgls command. The normal checks are read-only and do not need sudo. You may need elevated privileges to inspect cgroups or processes that your account cannot read, but privilege does not change what a unit contains.
1. Confirm the local command
Start with the version and help output. This catches an older system before you rely on options added in later releases:
$ systemd-cgls --version
systemd 255 (255.4-1ubuntu8.17)
$ systemd-cgls --help
The installed manpage describes systemd-cgls as a tree view of a selected Linux control group hierarchy. It shows member processes and descendant subgroups. Empty groups are hidden by default, and process names can be shortened unless you request full output.
Checkpoint
Confirm the binary used by your shell and record the version if you are putting the command into monitoring or a runbook:
$ command -v systemd-cgls
/usr/bin/systemd-cgls
$ systemd-cgls --version | head -n 1
systemd 255 (255.4-1ubuntu8.17)
2. View the relevant part of the hierarchy
With no argument, the command chooses its scope from the current directory. If the directory is beneath /sys/fs/cgroup/, it shows the cgroup represented by that directory. From an ordinary directory such as your home directory, it shows the full systemd hierarchy:
$ cd /tmp
$ systemd-cgls --no-pager
Control group /:
-.slice
├─init.scope
│ └─1 /sbin/init
└─system.slice
├─systemd-journald.service
│ └─455 /usr/lib/systemd/systemd-journald
└─...
Exact units, PIDs and tree branches vary by host. The useful check is the first line and the presence of the service or slice you are investigating. --no-pager keeps output in the terminal and makes redirection predictable.
For a narrower view, pass a cgroup path. A full path is unambiguous:
$ systemd-cgls --no-pager /sys/fs/cgroup/system.slice
Control group /system.slice:
├─systemd-journald.service
│ └─455 /usr/lib/systemd/systemd-journald
└─...
A path without the mount prefix is treated in the systemd control group hierarchy, but using the full path helps avoid confusion when another cgroup hierarchy is mounted.
3. Inspect one service by unit name
For service troubleshooting, use --unit rather than searching a large tree by eye:
$ systemd-cgls --no-pager --unit=systemd-journald.service
Unit systemd-journald.service (/system.slice/systemd-journald.service):
└─455 /usr/lib/systemd/systemd-journald
This selects the cgroup subtree for the named unit. It does not start, stop or reload the unit. Add more unit names when comparing several services:
$ systemd-cgls --no-pager --unit=systemd-journald.service systemd-udevd.service
If a name is not valid on this host, the command reports an error. Check the exact loaded unit name with systemctl list-units --type=service; do not silently replace a failed lookup with a similarly named service.
4. Make long process trees useful
Process command lines are ellipsised by default. Use -l or --full when the truncated argument is the detail you need:
$ systemd-cgls --no-pager --full --unit=systemd-journald.service
Unit systemd-journald.service (/system.slice/systemd-journald.service):
└─455 /usr/lib/systemd/systemd-journald
Use --all when an empty control group matters to your investigation. It changes visibility only; it does not create or remove groups:
$ systemd-cgls --no-pager --all --unit=systemd-journald.service
Kernel threads are omitted unless you add -k. That is usually the clearer default for service work. Include them when you are investigating kernel activity and understand that the output will become busier.
5. Check user units and containers separately
User units have their own selection option. Pass the exact user unit name, including its suffix:
$ systemd-cgls --no-pager --user-unit=backup.service
A missing user unit is not evidence that the system service is missing. Check the user manager's units with systemctl --user list-units, then repeat the lookup with the exact name.
When systemd manages a container, -M or --machine= limits the display to the cgroup area for that machine:
$ systemd-cgls --no-pager --machine=CONTAINER_NAME
Replace CONTAINER_NAME with the machine name reported by machinectl list. The command only inspects the selected area. It does not enter the container, execute a command there or alter its lifecycle.
6. Add IDs when the cgroup identity matters
On systemd 250 and later, -c or --cgroup-id= can include the numeric ID of each listed cgroup. The short form enables it; the long form accepts a boolean value:
$ systemd-cgls --no-pager --cgroup-id=yes --unit=systemd-journald.service
Likewise, -x or --xattr= controls whether extended-attribute information is shown. Both features default to off in the installed systemd 255 manpage. Use them when correlating output with tooling that records cgroup IDs or attributes, not as a general-purpose verbosity switch.
7. Handle permissions and output safely
A non-zero exit status means the query failed. Capture it when scripting:
$ systemd-cgls --no-pager --unit=systemd-journald.service
status=$?
if [ "$status" -ne 0 ]; then
printf 'systemd-cgls failed with status %s\n' "$status" >&2
exit "$status"
fi
Do not parse the decorative tree characters as a stable machine interface. For automation, prefer systemd or cgroup APIs designed for structured data, and use this command for human inspection. If access is denied, first confirm the unit or path. Only then retry with the minimum privilege required by your host policy:
$ sudo systemd-cgls --no-pager --unit=UNIT_NAME.service
This is a read-only diagnostic example. Do not use sudo as a way to guess unit names, and do not turn a service-disrupting command into a follow-up experiment while diagnosing the output. There is no undo step because the examples above do not change cgroups or services.
Done means
- You confirmed the installed systemd-cgls version and binary.
- You selected the intended scope: hierarchy, cgroup path, unit, user unit or machine.
- You used
--no-pagerfor repeatable terminal or captured output. - You know that empty groups, kernel threads and long process arguments are hidden or shortened by default.
- You treated non-zero status and permission errors as conditions to investigate, not as proof that a unit is absent.
- You made no service, cgroup, container or persistent configuration changes.