Compare commits

...

26 Commits

Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek dbca733213
Merge pull request #14571 from poettering/assorted-fixlets
two minor fixes for recent merges
2020-01-14 21:22:13 +01:00
Lennart Poettering 3fec552468 docs: rework HTML into GitHub Markdown table
Presumably this should render better on https://systemd.io/DISCOVERABLE_PARTITIONS then.

As pointed out on: https://github.com/systemd/systemd/pull/14390#issuecomment-574205631
2020-01-14 16:58:05 +01:00
Lennart Poettering c238a2f889 cgroup: minor comment improvement
As pointed out here:

https://github.com/systemd/systemd/pull/14564#discussion_r366305882
2020-01-14 16:57:51 +01:00
Lennart Poettering 550979c8ae
Merge pull request #14570 from keszybz/resource-docs
Modernize links to cgroups docs
2020-01-14 16:17:38 +01:00
Lennart Poettering be2bb14f00 logind: refuse overriding idle hint on tty sessions
Previously we'd allow marking TTY sessions as idle, but when the user
tried to unmark it as idle again it we'd just revert to automatic TTY
atime idle detection, thus making it impossible to mark the session as
non-idle, unless its TTY is atime-touched all the time. But of course,
marking a session as idle is pretty much fatal if you never can mark it
as non-idle again.

This change is triggred by bug reports such as this:

https://github.com/systemd/systemd/issues/14053

With this patch we will now output a clean, clear error message if a
client tries to manipulate the idle state of a non-graphical session.
This means we now have clear rules: "manual" idle logic for graphical
sessions, and TTY based ones for all others that have a TTY of some
form.

I considered allowing the idle state to be overriden both ways for tty
sessions but that's problematic: for sessions that are temporarily
upgraded from tty to graphical and thus suddenly want to manage their
own idle state we'd need to a way to detect when the upgrade goes away
and thus we should revert to old behaviour. Without reverting to the
previous TTY idle auto-magic we'd otherwise be stuck in an eternally
idle or eternally non-idle state, with really bad effects in case
auto-suspend is used. Thus, let's instead generate a proper error
message, saying clearly we don't support it.

(Also includes some other fixes and clean-ups in related code)

Closes: #14053
2020-01-14 16:11:39 +01:00
Zbigniew Jędrzejewski-Szmek 952805a9e3
Merge pull request #14564 from poettering/cgroup-realize-fix
pid1: cgroup realization fix
2020-01-14 15:52:56 +01:00
Zbigniew Jędrzejewski-Szmek ea7fe1d1c2
Merge pull request #14390 from poettering/gpt-var-tmp
introduce GPT partition types for /var and /var/tmp and support them for auto-discovery
2020-01-14 15:37:53 +01:00
Frantisek Sumsal de9a8fe18e systemctl: use format-table.[ch] for tables 2020-01-14 15:26:21 +01:00
Zbigniew Jędrzejewski-Szmek 7c286cd6a6
Merge pull request #14505 from poettering/refuse-on-failure
refuse OnFailure= deps on units that have no failure state
2020-01-14 14:19:04 +01:00
Zbigniew Jędrzejewski-Szmek 92d4af9dab
Merge pull request #14563 from poettering/less-the-markdown
trivial markdown fixlets
2020-01-14 13:23:50 +01:00
Lennart Poettering 48fd01e5f3 cgroup: drop redundant if check 2020-01-14 10:44:58 +01:00
Lennart Poettering e1e98911a8 cgroup: update only siblings that got realized once
Fixes: #14475
Replaces: #14554
2020-01-14 10:44:19 +01:00
Lennart Poettering 95ae4d1420 cgroup: drop unnecessary {} 2020-01-14 10:44:19 +01:00
Lennart Poettering a0d6590c4e cgroup: no need to cast dev_t to dev_t 2020-01-14 10:44:19 +01:00
Lennart Poettering 57f1030b13 cgroup: use log_warning_errno() where possible 2020-01-14 10:44:19 +01:00
Lennart Poettering b35ec8ded2 docs: uppercase all markdown document titles
For most we used uppercasing, but not for all. Let's stick to one rule,
and uppercase them all.
2020-01-14 10:14:11 +01:00
Lennart Poettering a0fadf66da docs: drop "The" in categorization titles of Markdown documentation
I think it makes sense to keep the "The" in place for the actual page's
title, but let's drop it from the categorization header, to make it
easier to find stuff, as the "The" isn't helpful to that.

In particular as we sometimes do it this and sometimes the other way so
far, hence let's stick to one common rule.
2020-01-14 10:11:19 +01:00
Zbigniew Jędrzejewski-Szmek 246be82bd4 man: link to specific sections of cgroups-v2 document
The document is rather huge, and a specific link is easier to consume. The form
is a bit strange because troff puts the symlink at the bottom, keyed by title,
so we need to use the same link target in all places.
2020-01-09 16:47:34 +01:00
Zbigniew Jędrzejewski-Szmek bb6d563a50 doc: link to html versions of cgroup docs
Also stop linking to some (obsolete) v1 documentation.
2020-01-09 16:47:34 +01:00
Lennart Poettering ab015b13df man: small casing fix 2020-01-09 11:04:41 +01:00
Lennart Poettering f2e5e70410 man: document that scope units can fail, but not due to process exit statusses
Let's clarify that scope units can fail, but not due to process exit
statusses.

This hopefully clears up some confusion that manifested in #14142: scope
units can fail, but for other reasons than assumed there.

Fixes: #14142
2020-01-09 11:04:27 +01:00
Lennart Poettering c80a9a33d0 core: clearly refuse OnFailure= deps on units that can't fail
Similar, refuse triggering deps on units that cannot trigger.

And rework how we ignore After= dependencies on device units, to work
the same way.

See: #14142
2020-01-09 11:03:53 +01:00
Lennart Poettering 27cc3c9d76 update TODO 2019-12-23 14:45:03 +01:00
Lennart Poettering 31ca5166b6 man: document /var/tmp/ and /var/ handling in systemd-gpt-auto-generator man page
And some other fixes and additions.
2019-12-23 14:44:48 +01:00
Lennart Poettering 19ac32cdd6 docs: import discoverable partitions spec
This was previously available here:

https://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/

Let's pull it into our repository.
2019-12-23 14:44:33 +01:00
Lennart Poettering d4dffb8533 dissect: introduce new recognizable partition types for /var and /var/tmp
This has been requested many times before. Let's add it finally.

GPT auto-discovery for /var is a bit more complex than for other
partition types: the other partitions can to some degree be shared
between multiple OS installations on the same disk (think: swap, /home,
/srv). However, /var is inherently something bound to an installation,
i.e. specific to its identity, or actually *is* its identity, and hence
something that cannot be shared.

To deal with this this new code is particularly careful when it comes to
/var: it will not mount things blindly, but insist that the UUID of the
partition matches a hashed version of the machine-id of the
installation, so that each installation has a very specific /var
associated with it, and would never use any other. (We actually use
HMAC-SHA256 on the GPT partition type for /var, keyed by the machine-id,
since machine-id is something we want to keep somewhat private).

Setting the right UUID for installations takes extra care. To make
things a bit simpler to set up, we avoid this safety check for nspawn
and RootImage= in unit files, under the assumption that such container
and service images unlikely will have multiple installations on them.
The check is hence only required when booting full machines, i.e. in
in systemd-gpt-auto-generator.

To help with putting together images for full machines, PR #14368
introduces a repartition tool that can automatically fill in correctly
calculated UUIDs on first boot if images have the var partition UUID
initialized to all zeroes. With that in place systems can be put
together in a way that on first boot the machine ID is determined and
the partition table automatically adjusted to have the /var partition
with the right UUID.
2019-12-23 14:43:59 +01:00
44 changed files with 733 additions and 529 deletions

16
TODO
View File

@ -19,6 +19,11 @@ Janitorial Clean-ups:
Features:
* when dissecting images, warn about unrecognized partition flags
* honour specifiers in unit files that resolve to some very basic
/etc/os-release data, such as ID, VERSION_ID, BUILD_ID, VARIANT_ID.
* socket units: allow creating a udev monitor socket with ListenDevices= or so,
with matches, then actviate app thorugh that passing socket oveer
@ -44,8 +49,6 @@ Features:
shouldn't operate in a volatile mode unless we got told so from a trusted
source.
* look for /var/tmp automatically via gpt auto discovery
* figure out automatic partition discovery when combining writable root dir
with immutable /usr
@ -416,8 +419,6 @@ Features:
"systemd-gdb" for attaching to the start-up of any system service in its
natural habitat.
* maybe introduce gpt auto discovery for /var/tmp?
* maybe add gpt-partition-based user management: each user gets his own
LUKS-encrypted GPT partition with a new GPT type. A small nss module
enumerates users via udev partition enumeration. UIDs are assigned in a fixed
@ -427,13 +428,6 @@ Features:
with stateless/read-only/verity-enabled root. (other idea: do this based on
loopback files in /home, without GPT involvement)
* gpt-auto logic: introduce support for discovering /var matching an image. For
that, use a partition type UUID that is hashed from the OS name (as encoded
in /etc/os-release), the architecture, and 4 new bits from the gpt flags
field of the root partition. This way can easily support multiple OS
installations on the same GPT partition table, without problems with
unmatched /var partitions.
* gpt-auto logic: related to the above, maybe support a "secondary" root
partition, that is mounted to / and is writable, and where the actual root's
/usr is mounted into.

View File

@ -1,5 +1,5 @@
---
title: The Boot Loader Interface
title: Boot Loader Interface
category: Booting
layout: default
---

View File

@ -1,5 +1,5 @@
---
title: The Boot Loader Specification
title: Boot Loader Specification
category: Booting
layout: default
---

View File

@ -21,10 +21,10 @@ comprehensive up-to-date information about all this, particular in light of the
poor implementations of the components interfacing with systemd of current
container managers.
Before you read on, please make sure you read the low-level [kernel
documentation about
cgroup v2](https://www.kernel.org/doc/Documentation/cgroup-v2.txt). This
documentation then adds in the higher-level view from systemd.
Before you read on, please make sure you read the low-level kernel
documentation about the
[unified cgroup hierarchy](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html).
This document then adds in the higher-level view from systemd.
This document augments the existing documentation we already have:

View File

@ -1,5 +1,5 @@
---
title: The systemd Community Conduct Guidelines
title: systemd Community Conduct Guidelines
category: Contributing
layout: default
---

View File

@ -1,5 +1,5 @@
---
title: The Container Interface
title: Container Interface
category: Interfaces
layout: default
---

View File

@ -0,0 +1,213 @@
---
title: Discoverable Partitions Specification
category: Concepts
layout: default
---
# The Discoverable Partitions Specification
_TL;DR: Let's automatically discover, mount and enable the root partition,
`/home/`, `/srv/`, `/var/` and `/var/tmp/` and the swap partitions based on
GUID Partition Tables (GPT)!_
The GUID Partition Table (GPT) is mandatory on EFI systems. It allows
identification of partition types with UUIDs. So far Linux has made little use
of this, and mostly just defined one UUID for file system/data partitions and
another one for swap partitions. With this specification, we introduce
additional partition types to enable automatic discovery of partitions and
their intended mountpoint. This has many benefits:
* OS installers can automatically discover and make sense of partitions of
existing Linux installations.
* The OS can discover and mount the necessary file systems with a non-existing
or incomplete `/etc/fstab` file and without the `root=` kernel command line
option.
* Container managers (such as nspawn and libvirt-lxc) can decode and set up
file systems contained in GPT disk images automatically and mount them to the
right places, thus allowing booting the same, identical images on bare-metal
and in Linux containers. This enables true, natural portability of disk
images between physical machines and Linux containers.
* As a help to administrators and users partition manager tools can show more
descriptive information about partitions tables.
Note that the OS side of this specification is currently implemented in
[systemd](http://systemd.io/) 211 and newer in the
[systemd-auto-gpt-generator(8)](http://www.freedesktop.org/software/systemd/man/systemd-gpt-auto-generator.html)
generator tool. Note that automatic discovery of the root only works if the
boot loader communicates this information to the OS, by implementing the [Boot
Loader
Interface](https://systemd.io/BOOT_LOADER_INTERFACE).
## Defined Partition Type UUIDs
| Partition Type UUID | Name | Allowed File Systems | Explanation |
|---------------------|------|----------------------|-------------|
| `44479540-f297-41b2-9af7-d131d5f0458a` | _Root Partition (x86)_ | Any native, optionally in LUKS | On systems with matching architecture, the first partition with this type UUID on the disk containing the active EFI ESP is automatically mounted to the root directory <tt>/</tt>. If the partition is encrypted with LUKS or has dm-verity integrity data (see below), the device mapper file will be named `/dev/mapper/root`. |
| `4f68bce3-e8cd-4db1-96e7-fbcaf984b709` | _Root Partition (x86-64)_ | ditto | ditto |
| `69dad710-2ce4-4e3c-b16c-21a1d49abed3` | _Root Partition (32-bit ARM)_ | ditto | ditto |
| `b921b045-1df0-41c3-af44-4c6f280d3fae` | _Root Partition (64-bit ARM/AArch64)_ | ditto | ditto |
| `993d8d3d-f80e-4225-855a-9daf8ed7ea97` | _Root Partition (Itanium/IA-64)_ | ditto | ditto |
| `d13c5d3b-b5d1-422a-b29f-9454fdc89d76` | _Root Verity Partition (x86)_ | A dm-verity superblock followed by hash data | On systems with matching architecture, contains dm-verity integrity hash data for the matching root partition. If this feature is used the partition UUID of the root partition should be the first 128bit of the root hash of the dm-verity hash data, and the partition UUID of this dm-verity partition should be the final 128bit of it, so that the root partition and its verity partition can be discovered easily, simply by specifying the root hash. |
| `2c7357ed-ebd2-46d9-aec1-23d437ec2bf5` | _Root Verity Partition (x86-64)_ | ditto | ditto |
| `7386cdf2-203c-47a9-a498-f2ecce45a2d6` | _Root Verity Partition (32-bit ARM)_ | ditto | ditto |
| `df3300ce-d69f-4c92-978c-9bfb0f38d820` | _Root Verity Partition (64-bit ARM/AArch64)_ | ditto | ditto |
| `86ed10d5-b607-45bb-8957-d350f23d0571` | _Root Verity Partition (Itanium/IA-64)_ | ditto | ditto |
| `933ac7e1-2eb4-4f13-b844-0e14e2aef915` | _Home Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/home/`. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/home`. |
| `3b8f8425-20e0-4f3b-907f-1a25a76f98e8` | _Server Data Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/srv/`. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/srv`. |
| `4d21b016-b534-45c2-a9fb-5c16e091fd2d` | _Variable Data Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/var/` — under the condition that its partition UUID matches the first 128 bit of `HMAC-SHA256(machine-id, 0x4d21b016b53445c2a9fb5c16e091fd2d)` (i.e. the SHA256 HMAC hash of the binary type UUID keyed by the machine ID as read from [`/etc/machine-id`](https://www.freedesktop.org/software/systemd/man/machine-id.html). This special requirement is made because `/var/` (unlike the other partition types listed here) is inherently private to a specific installation and cannot possibly be shared between multiple OS installations on the same disk, and thus should be bound to a specific instance of the OS, identified by its machine ID. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/var`. |
| `7ec6f557-3bc5-4aca-b293-16ef5df639d1` | _Temporary Data Partition_ | Any native, optionally in LUKS | The first partition with this type UUID on the disk containing the root partition is automatically mounted to `/var/tmp/`. If the partition is encrypted with LUKS, the device mapper file will be named `/dev/mapper/tmp`. Note that the intended mount point is indeed `/var/tmp/`, not `/tmp/`. The latter is typically maintained in memory via <tt>tmpfs</tt> and does not require a partition on disk. In some cases it might be desirable to make `/tmp/` persistent too, in which case it is recommended to make it a symlink or bind mount to `/var/tmp/`, thus not requiring its own partition type UUID. |
| `0657fd6d-a4ab-43c4-84e5-0933c84b4f4f` | _Swap_ | Swap | All swap partitions on the disk containing the root partition are automatically enabled. |
| `c12a7328-f81f-11d2-ba4b-00a0c93ec93b` | _EFI System Partition_ | VFAT | The ESP used for the current boot is automatically mounted to `/efi/` (or `/boot/` as fallback), unless a different partition is mounted there (possibly via `/etc/fstab`, or because the Extended Boot Loader Partition — see below — exists) or the directory is non-empty on the root disk. This partition type is defined by the [UEFI Specification](http://www.uefi.org/specifications). |
| `bc13c2ff-59e6-4262-a352-b275fd6f7172` | _Extended Boot Loader Partition_ | Typically VFAT | The Extended Boot Loader Partition (XBOOTLDR) used for the current boot is automatically mounted to <tt>/boot/</tt>, unless a different partition is mounted there (possibly via <tt>/etc/fstab</tt>) or the directory is non-empty on the root disk. This partition type is defined by the [Boot Loader Specification](https://systemd.io/BOOT_LOADER_SPECIFICATION). |
| `0fc63daf-8483-4772-8e79-3d69d8477de4` | _Other Data Partitions_ | Any native, optionally in LUKS | No automatic mounting takes place for other Linux data partitions. This partition type should be used for all partitions that carry Linux file systems. The installer needs to mount them explicitly via entries in <tt>/etc/fstab</tt>. Optionally, these partitions may be encrypted with LUKS. |
Other GPT type IDs might be used on Linux, for example to mark software RAID or
LVM partitions. The definitions of those GPT types is outside of the scope of
this specification.
## Partition Names
For partitions of the types listed above it is recommended to use
human-friendly, descriptive partition names in the GPT partition table, for
example "*Home*", "*Server* *Data*", "*Fedora* *Root*" and similar, possibly
localized.
## Partition Flags
For the root, server data, home, variable data, temporary data and swap
partitions, the partition flag bit 63 ("*no-auto*") may be used to turn off
auto-discovery for the specific partition. If set, the partition will not be
automatically mounted or enabled.
For the root, server data, home, variable data and temporary data partitions,
the partition flag bit 60 ("*read-only*") may be used to mark a partition for
read-only mounts only. If set, the partition will be mounted read-only instead
of read-write. Note that the variable data partition and the temporary data
partition will generally not be able to serve their purpose if marked
read-only, since by their very definition they are supposed to be mutable. (The
home and server data partitions are generally assumed to be mutable as well,
but the requirement for them is not equally strong.) Because of that, while the
read-only flag is defined and supported, it's almost never a good idea to
actually use it for these partitions.
Note that these two flag definitions happen to map nicely to the ones used by
Microsoft Basic Data Partitions.
## Suggested Mode of Operation
An *installer* that repartitions the hard disk _should_ use the above UUID
partition types for appropriate partitions it creates.
An *installer* which supports a "manual partitioning" interface _may_ choose to
pre-populate the interface with swap, `/home/`, `/srv/`, `/var/tmp/` partitions
of pre-existing Linux installations, identified with the GPT type UUIDs
above. The installer should not pre-populate such an interface with any
identified root or `/var/` partition unless the intention is to overwrite an
existing operating system that might be installed.
An *installer* _may_ omit creating entries in `/etc/fstab` for root, `/home/`,
`/srv/`, `/var/`, `/var/tmp` and for the swap partitions if they use these UUID
partition types, and are the first partitions on the disk of each type. If the
ESP shall be mounted to `/efi/` (or `/boot/`), it may additionally omit
creating the entry for it in `/etc/fstab`. If an extended boot partition is
used, or if the EFI partition shall not be mounted to `/efi/` or `/boot/`, it
_must_ create `/etc/fstab` entries for them. If other partitions are used (for
example for `/usr/` or `/var/lib/mysql/`), the installer _must_ register these
in `/etc/fstab`. The `root=` parameter passed to the kernel by the boot loader
may be omitted if the root partition is the first one on the disk of its type.
If the root partition is not the first one on the disk, the `root=` parameter
_must_ be passed to the kernel by the boot loader. An installer that mounts a
root, `/home/`, `/srv/`, `/var/`, or `/var/tmp/` file system with the partition
types defined as above which contains a LUKS header _must_ call the device
mapper device "root", "home", "srv", "var" or "tmp", respectively. This is
necessary to ensure that the automatic discovery will never result in different
device mapper names than any static configuration by the installer, thus
eliminating possible naming conflicts and ambiguities.
An *operating* *system* _should_ automatically discover and mount the first
root partition that does not have the no-auto flag set (as described above) by
scanning the disk containing the currently used EFI ESP. It _should_
automatically discover and mount the first `/home/`, `/srv/`, `/var/`,
`/var/tmp/` and swap partitions that do not have the no-auto flag set by
scanning the disk containing the discovered root partition. It should
automatically discover and mount the partition containing the currently used
EFI ESP to `/efi/` (or `/boot/` as fallback). It should automatically discover
and mount the partition containing the currently used Extended Boot Loader
Partition to `/boot/`. It _should not_ discover or automatically mount
partitions with other UUID partition types, or partitions located on other
disks, or partitions with the no-auto flag set. User configuration shall
always override automatic discovery and mounting. If a root, `/home/`,
`/srv/`, `/boot/`, `/var/`, `/var/tmp/`, `/efi/`, `/boot/` or swap partition is
listed in `/etc/fstab` or with `root=` on the kernel command line, it _must_
take precedence over automatically discovered partitions. If a `/home/`,
`/srv/`, `/boot/`, `/var/`, `/var/tmp/`, `/efi/` or `/boot/` directory is found
to be populated already in the root partition, the automatic discovery _must
not_ mount any discovered file system over it.
A *container* *manager* should automatically discover and mount the root,
`/home/`, `/srv/`, `/var/`, `/var/tmp/` partitions inside a container disk
image. It may choose to mount any discovered ESP and/or XBOOOTLDR partition to
`/efi/` or `/boot/`. It should ignore any swap should they be included in a
container disk image.
If a btrfs file system is automatically discovered and mounted by the operating
system/container manager it will be mounted with its *default* subvolume. The
installer should make sure to set the default subvolume correctly using "btrfs
subvolume set-default".
## Sharing of File Systems between Installations
If two Linux-based operating systems are installed on the same disk, the scheme
above suggests that they may share the swap, `/home/`, `/srv/`, `/var/tmp/`,
ESP, XBOOTLDR. However, they should each have their own root and `/var/`
partition.
## Frequently Asked Questions
### Why are you taking my `/etc/fstab` away?
We are not. `/etc/fstab` always overrides automatic discovery and is indeed
mentioned in the specifications. We are simply trying to make the boot and
installation processes of Linux a bit more robust and self-descriptive.
### Why did you only define the root partition for x86, x86-64, ARM, ARM64, ia64?
The automatic discovery of the root partition is defined to operate on the disk
containing the current EFI System Partition (ESP). Since EFI only exists on
x86, x86-64, ia64, and ARM so far, we only defined root partition UUIDs for
these architectures. Should EFI become more common on other architectures, we
can define additional UUIDs for them.
### Why define distinct root partition UUIDs for the various architectures?
This allows disk images that may be booted on multiple architectures to use
discovery of the appropriate root partition on each architecture.
### Doesn't this break multi-boot scenarios?
No, it doesn't. The specification says that installers may not stop creating
`/etc/fstab` or stop including `root=` on the kernel command line, unless the used
partitions are the first ones of their type on the disk. Additionally,
`/etc/fstab` and `root=` both override automatic discovery. Multi-boot is hence
well supported, since it doesn't change anything for anything but the first
installation.
That all said, it's not expected that generic installers generally stop setting
`root=` and creating `/etc/fstab` anyway. The option to drop these configuration
bits is primarily something for appliance-like devices. However, generic
installers should *still* set the right GPT partition types for the partitions
they create so that container managers, partition tools and administrators can
benefit. Phrased differently, this specification introduces A) the
*recommendation* to use the newly defined partition types to tag things
properly and B) the *option* to then drop `root=` and `/etc/fstab`. While we
advertise A) to *all* installers, we only propose B) for simpler,
appliance-like installations.
### What partitioning tools will create a DPS-compliant partition table?
As of util-linux 2.25.2, the fdisk tool provides type codes to create the root,
home, and swap partitions that the DPS expects, but the gdisk tool (version
0.8.10) and its variants do not support creation of a root file system with a
matching type code. By default, fdisk will create an old-style MBR, not a GPT,
so typing 'l' to list partition types will not show the choices that the root
partition with the correct UUID. You must first create an empty GPT and then
type 'l' in order for the DPS-compliant type codes to be available.

View File

@ -165,7 +165,7 @@ requirements are made for an image that can be attached/detached with
an image with a partition table understood by the Linux kernel with only a
single partition defined, or alternatively, a GPT partition table with a set
of properly marked partitions following the [Discoverable Partitions
Specification](https://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/).
Specification](https://systemd.io/DISCOVERABLE_PARTITIONS).
3. The image must at least contain one matching unit file, with the right name
prefix and suffix (see above). The unit file is searched in the usual paths,

View File

@ -1,9 +1,9 @@
---
title: Reporting of security vulnerabilities
title: Reporting of Security Vulnerabilities
category: Contributing
layout: default
---
# Reporting of security vulnerabilities
# Reporting of Security Vulnerabilities
If you discover a security vulnerability, we'd appreciate a non-public disclosure. The [issue tracker](https://github.com/systemd/systemd/issues) and [systemd-devel mailing list](https://lists.freedesktop.org/mailman/listinfo/systemd-devel) are fully public. If you need to reach systemd developers in a non-public way, report the issue to the [systemd-security@redhat.com](mailto:systemd-security@redhat.com) mailing list. The disclosure will be coordinated with distributions.

View File

@ -1,10 +1,10 @@
---
title: Testing systemd using sanitizers
title: Testing systemd Using Sanitizers
category: Contributing
layout: default
---
# Testing systemd using sanitizers
# Testing systemd Using Sanitizers
To catch the *nastier* kind of bugs, you can run your code with [Address Sanitizer](https://clang.llvm.org/docs/AddressSanitizer.html)
and [Undefined Behavior Sanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html).

View File

@ -1,10 +1,10 @@
---
title: What settings are currently available for transient units?
title: What Settings Are Currently Available For Transient Units?
category: Interfaces
layout: default
---
# What settings are currently available for transient units?
# What Settings Are Currently Available For Transient Units?
Our intention is to make all settings that are available as unit file settings
also available for transient units, through the D-Bus API. At the moment,

View File

@ -17,11 +17,9 @@
<refnamediv>
<refname>systemd-gpt-auto-generator</refname>
<refpurpose>Generator for automatically discovering
and mounting root, <filename>/home</filename> and
<filename>/srv</filename> partitions, as well as
discovering and enabling swap partitions, based on GPT
partition type GUIDs.</refpurpose>
<refpurpose>Generator for automatically discovering and mounting root, <filename>/home/</filename>,
<filename>/srv/</filename>, <filename>/var/</filename> and <filename>/var/tmp/</filename> partitions, as
well as discovering and enabling swap partitions, based on GPT partition type GUIDs.</refpurpose>
</refnamediv>
<refsynopsisdiv>
@ -32,11 +30,11 @@
<title>Description</title>
<para><filename>systemd-gpt-auto-generator</filename> is a unit generator that automatically discovers
root, <filename>/home/</filename>, <filename>/srv/</filename>, the EFI System Partition, the Extended
Boot Loader Partition and swap partitions and creates mount and swap units for them, based on the
partition type GUIDs of GUID partition tables (GPT), see <ulink
url="https://uefi.org/specifications">UEFI Specification</ulink>, chapter 5. It implements the <ulink
url="https://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/">Discoverable Partitions
root, <filename>/home/</filename>, <filename>/srv/</filename>, <filename>/var/</filename>,
<filename>/var/tmp/</filename>, the EFI System Partition, the Extended Boot Loader Partition and swap
partitions and creates mount and swap units for them, based on the partition type GUIDs of GUID partition
tables (GPT), see <ulink url="https://uefi.org/specifications">UEFI Specification</ulink>, chapter 5. It
implements the <ulink url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partitions
Specification</ulink>. Note that this generator has no effect on non-GPT systems, and on specific mount
points that are directories already containing files. Also, on systems where the units are explicitly
configured (for example, listed in <citerefentry
@ -45,10 +43,12 @@
created.</para>
<para>This generator will only look for the root partition on the same physical disk the EFI System
Partition (ESP) is located on. Note that support from the boot loader is required: EFI variable
<varname>LoaderDevicePartUUID-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f</varname> is used to determine from
which partition, and hence the disk from which the system was booted. If the boot loader does not set
this variable, this generator will not be able to autodetect the root partition.</para>
Partition (ESP) is located on. Note that support from the boot loader is required: the EFI variable
<varname>LoaderDevicePartUUID</varname> of the <constant>4a67b082-0a4c-41cf-b6c7-440b29bb8c4f</constant>
vendor UUID is used to determine from which partition, and hence the disk from which the system was
booted. If the boot loader does not set this variable, this generator will not be able to autodetect the
root partition. See the <ulink url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader
Interface</ulink> for details.</para>
<para>Similarly, this generator will only look for the other partitions on the same physical disk as the
root partition. In this case, boot loader support is not required. These partitions will not be searched
@ -113,13 +113,25 @@
<entry>933ac7e1-2eb4-4f13-b844-0e14e2aef915</entry>
<entry>Home Partition</entry>
<entry><filename>/home/</filename></entry>
<entry>The first home partition on the disk the root partition is located on is mounted to <filename>/home</filename>.</entry>
<entry>The first home partition on the disk the root partition is located on is mounted to <filename>/home/</filename>.</entry>
</row>
<row>
<entry>3b8f8425-20e0-4f3b-907f-1a25a76f98e8</entry>
<entry>Server Data Partition</entry>
<entry><filename>/srv/</filename></entry>
<entry>The first server data partition on the disk the root partition is located on is mounted to <filename>/srv</filename>.</entry>
<entry>The first server data partition on the disk the root partition is located on is mounted to <filename>/srv/</filename>.</entry>
</row>
<row>
<entry>4d21b016-b534-45c2-a9fb-5c16e091fd2d</entry>
<entry>Variable Data Partition</entry>
<entry><filename>/var/</filename></entry>
<entry>The first variable data partition on the disk the root partition is located on is mounted to <filename>/var/</filename> — under the condition its partition UUID matches the first 128 bit of the HMAC-SHA256 of the GPT type uuid of this partition keyed by the machine ID of the installation stored in <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</entry>
</row>
<row>
<entry>7ec6f557-3bc5-4aca-b293-16ef5df639d1</entry>
<entry>Temporary Data Partition</entry>
<entry><filename>/var/tmp/</filename></entry>
<entry>The first temporary data partition on the disk the root partition is located on is mounted to <filename>/var/tmp/</filename>.</entry>
</row>
<row>
<entry>0657fd6d-a4ab-43c4-84e5-0933c84b4f4f</entry>
@ -131,13 +143,13 @@
<entry>c12a7328-f81f-11d2-ba4b-00a0c93ec93b</entry>
<entry>EFI System Partition (ESP)</entry>
<entry><filename>/efi/</filename> or <filename>/boot/</filename></entry>
<entry>The first ESP located on the disk the root partition is located on is mounted to <filename>/boot</filename> or <filename>/efi</filename>, see below.</entry>
<entry>The first ESP located on the disk the root partition is located on is mounted to <filename>/boot/</filename> or <filename>/efi/</filename>, see below.</entry>
</row>
<row>
<entry>bc13c2ff-59e6-4262-a352-b275fd6f7172</entry>
<entry>Extended Boot Loader Partition</entry>
<entry><filename>/boot/</filename></entry>
<entry>The first Extended Boot Loader Partition is mounted to <filename>/boot</filename>, see below.</entry>
<entry>The first Extended Boot Loader Partition is mounted to <filename>/boot/</filename>, see below.</entry>
</row>
</tbody>
</tgroup>
@ -164,14 +176,14 @@
<row>
<entry><constant>GPT_FLAG_READ_ONLY</constant></entry>
<entry>0x1000000000000000</entry>
<entry><filename>/</filename>, <filename>/home/</filename>, <filename>/srv/</filename>, Extended Boot Loader Partition</entry>
<entry><filename>/</filename>, <filename>/home/</filename>, <filename>/srv/</filename>, <filename>/var/</filename>, <filename>/var/tmp/</filename>, Extended Boot Loader Partition</entry>
<entry>Partition is mounted read-only</entry>
</row>
<row>
<entry><constant>GPT_FLAG_NO_AUTO</constant></entry>
<entry>0x8000000000000000</entry>
<entry><filename>/</filename>, <filename>/home/</filename>, <filename>/srv/</filename>, Extended Boot Loader Partition</entry>
<entry><filename>/</filename>, <filename>/home/</filename>, <filename>/srv/</filename>, <filename>/var/</filename>, <filename>/var/tmp/</filename>, Extended Boot Loader Partition</entry>
<entry>Partition is not mounted automatically</entry>
</row>
@ -185,11 +197,12 @@
</tgroup>
</table>
<para>The <filename>/home/</filename> and <filename>/srv/</filename> partitions may be encrypted in LUKS
format. In this case, a device mapper device is set up under the names
<filename>/dev/mapper/home</filename> and <filename>/dev/mapper/srv</filename>. Note that this might
create conflicts if the same partition is listed in <filename>/etc/crypttab</filename> with a different
device mapper device name.</para>
<para>The <filename>/home/</filename>, <filename>/srv/</filename>, <filename>/var/</filename> and
<filename>/var/tmp/</filename> partitions may be encrypted in LUKS format. In this case, a device mapper
device is set up under the names <filename>/dev/mapper/home</filename>,
<filename>/dev/mapper/srv</filename>, <filename>/dev/mapper/var</filename> and
<filename>/dev/mapper/tmp</filename>. Note that this might create conflicts if the same partition is
listed in <filename>/etc/crypttab</filename> with a different device mapper device name.</para>
<para>When systemd is running in the initrd the <filename>/</filename> partition may be encrypted in LUKS
format as well. In this case, a device mapper device is set up under the name <filename>/dev/mapper/root</filename>,
@ -209,7 +222,7 @@
<para>If the disk contains an Extended Boot Loader partition, as defined in the <ulink
url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink>, it is made
available at <filename>/boot</filename> (by means of an automount point, similar to the ESP, see
available at <filename>/boot/</filename> (by means of an automount point, similar to the ESP, see
above). If both an EFI System Partition and an Extended Boot Loader partition exist the latter is
preferably mounted to <filename>/boot/</filename>. Make sure to create both <filename>/efi/</filename>
and <filename>/boot/</filename> to ensure both partitions are mounted.</para>
@ -269,6 +282,7 @@
<citerefentry><refentrytitle>systemd.swap</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-cryptsetup@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>btrfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>

View File

@ -288,7 +288,7 @@
a server data partition which are mounted to the appropriate
places in the container. All these partitions must be
identified by the partition types defined by the <ulink
url="https://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/">Discoverable
url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable
Partitions Specification</ulink>.</para></listitem>
<listitem><para>No partition table, and a single file system spanning the whole image.</para></listitem>

View File

@ -117,12 +117,12 @@
<varlistentry>
<term><varname>RootImage=</varname></term>
<listitem><para>Takes a path to a block device node or regular file as argument. This call is similar to
<varname>RootDirectory=</varname> however mounts a file system hierarchy from a block device node or loopback
file instead of a directory. The device node or file system image file needs to contain a file system without a
partition table, or a file system within an MBR/MS-DOS or GPT partition table with only a single
Linux-compatible partition, or a set of file systems within a GPT partition table that follows the <ulink
url="https://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/">Discoverable Partitions
<listitem><para>Takes a path to a block device node or regular file as argument. This call is similar
to <varname>RootDirectory=</varname> however mounts a file system hierarchy from a block device node
or loopback file instead of a directory. The device node or file system image file needs to contain a
file system without a partition table, or a file system within an MBR/MS-DOS or GPT partition table
with only a single Linux-compatible partition, or a set of file systems within a GPT partition table
that follows the <ulink url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partitions
Specification</ulink>.</para>
<para>When <varname>DevicePolicy=</varname> is set to <literal>closed</literal> or

View File

@ -79,7 +79,7 @@
</row>
<row>
<entry><constant>sl</constant></entry>
<entry>serial line IP (slip)</entry>
<entry>Serial line IP (slip)</entry>
</row>
<row>
<entry><constant>wl</constant></entry>

View File

@ -82,10 +82,10 @@
<refsect1>
<title>Unified and Legacy Control Group Hierarchies</title>
<para>The unified control group hierarchy is the new version of kernel control group interface, see <ulink
url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>. Depending on the resource type,
there are differences in resource control capabilities. Also, because of interface changes, some resource types
have separate set of options on the unified hierarchy.</para>
<para>The unified control group hierarchy is the new version of kernel control group interface, see
<ulink url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html">Control Groups v2</ulink>.
Depending on the resource type, there are differences in resource control capabilities. Also, because of
interface changes, some resource types have separate set of options on the unified hierarchy.</para>
<para>
<variablelist>
@ -126,11 +126,11 @@
application.</para>
<para>Legacy control group hierarchy (see <ulink
url="https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt">cgroups.txt</ulink>), also called cgroup-v1,
doesn't allow safe delegation of controllers to unprivileged processes. If the system uses the legacy control group
hierarchy, resource control is disabled for systemd user instance, see
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
</para>
url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/">Control Groups version 1</ulink>),
also called cgroup-v1, doesn't allow safe delegation of controllers to unprivileged processes. If the
system uses the legacy control group hierarchy, resource control is disabled for the systemd user
instance, see
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
</refsect1>
<refsect1>
@ -165,8 +165,8 @@
is used on the system. These options take an integer value and control the <literal>cpu.weight</literal>
control group attribute. The allowed range is 1 to 10000. Defaults to 100. For details about this control
group attribute, see <ulink
url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink> and <ulink
url="https://www.kernel.org/doc/Documentation/scheduler/sched-design-CFS.txt">sched-design-CFS.txt</ulink>.
url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html">Control Groups v2</ulink> and <ulink
url="https://www.kernel.org/doc/html/latest/scheduler/sched-design-CFS.html">CFS Scheduler</ulink>.
The available CPU time is split up among all units within one slice relative to their CPU time weight.</para>
<para>While <varname>StartupCPUWeight=</varname> only applies to the startup phase of the system,
@ -187,7 +187,7 @@
available on one CPU. Use values &gt; 100% for allotting CPU time on more than one CPU. This controls the
<literal>cpu.max</literal> attribute on the unified control group hierarchy and
<literal>cpu.cfs_quota_us</literal> on legacy. For details about these control group attributes, see <ulink
url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink> and <ulink
url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html">Control Groups v2</ulink> and <ulink
url="https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt">sched-bwc.txt</ulink>.</para>
<para>Example: <varname>CPUQuota=20%</varname> ensures that the executed processes will never get more than
@ -208,8 +208,8 @@
<para>This controls the second field of <literal>cpu.max</literal> attribute on the unified control group hierarchy
and <literal>cpu.cfs_period_us</literal> on legacy. For details about these control group attributes, see
<ulink url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink> and
<ulink url="https://www.kernel.org/doc/Documentation/scheduler/sched-design-CFS.txt">sched-design-CFS.txt</ulink>.</para>
<ulink url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html">Control Groups v2</ulink> and
<ulink url="https://www.kernel.org/doc/html/latest/scheduler/sched-design-CFS.html">CFS Scheduler</ulink>.</para>
<para>Example: <varname>CPUQuotaPeriodSec=10ms</varname> to request that the CPU quota is measured in periods of 10ms.</para>
</listitem>
@ -274,7 +274,7 @@
useful in order to always inherit all of the protection afforded by ancestors.
This controls the <literal>memory.min</literal> control group attribute. For details about this
control group attribute, see <ulink
url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>.</para>
url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html#memory-interface-files">Memory Interface Files</ulink>.</para>
<para>This setting is supported only if the unified control group hierarchy is used and disables
<varname>MemoryLimit=</varname>.</para>
@ -300,7 +300,7 @@
useful in order to always inherit all of the protection afforded by ancestors.
This controls the <literal>memory.low</literal> control group attribute. For details about this
control group attribute, see <ulink
url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>.</para>
url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html#memory-interface-files">Memory Interface Files</ulink>.</para>
<para>This setting is supported only if the unified control group hierarchy is used and disables
<varname>MemoryLimit=</varname>.</para>
@ -325,7 +325,7 @@
system. If assigned the
special value <literal>infinity</literal>, no memory throttling is applied. This controls the
<literal>memory.high</literal> control group attribute. For details about this control group attribute, see
<ulink url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>.</para>
<ulink url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html#memory-interface-files">Memory Interface Files</ulink>.</para>
<para>This setting is supported only if the unified control group hierarchy is used and disables
<varname>MemoryLimit=</varname>.</para>
@ -346,7 +346,7 @@
percentage value may be specified, which is taken relative to the installed physical memory on the system. If
assigned the special value <literal>infinity</literal>, no memory limit is applied. This controls the
<literal>memory.max</literal> control group attribute. For details about this control group attribute, see
<ulink url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>.</para>
<ulink url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html#memory-interface-files">Memory Interface Files</ulink>.</para>
<para>This setting replaces <varname>MemoryLimit=</varname>.</para>
</listitem>
@ -362,7 +362,7 @@
parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. If assigned the
special value <literal>infinity</literal>, no swap limit is applied. This controls the
<literal>memory.swap.max</literal> control group attribute. For details about this control group attribute,
see <ulink url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>.</para>
see <ulink url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html#memory-interface-files">Memory Interface Files</ulink>.</para>
<para>This setting is supported only if the unified control group hierarchy is used and disables
<varname>MemoryLimit=</varname>.</para>
@ -397,10 +397,10 @@
of tasks or a percentage value that is taken relative to the configured maximum number of tasks on the
system. If assigned the special value <literal>infinity</literal>, no tasks limit is applied. This controls
the <literal>pids.max</literal> control group attribute. For details about this control group attribute, see
<ulink url="https://www.kernel.org/doc/Documentation/cgroup-v1/pids.txt">pids.txt</ulink>.</para>
<ulink url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/pids.html">Process Number Controller</ulink>.
</para>
<para>The
system default for this setting may be controlled with
<para>The system default for this setting may be controlled with
<varname>DefaultTasksMax=</varname> in
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
</listitem>
@ -431,8 +431,9 @@
hierarchy is used on the system. Takes a single weight value (between 1 and 10000) to set the default block
I/O weight. This controls the <literal>io.weight</literal> control group attribute, which defaults to
100. For details about this control group attribute, see <ulink
url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>. The available I/O
bandwidth is split up among all units within one slice relative to their block I/O weight.</para>
url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html#io-interface-files">IO Interface Files</ulink>.
The available I/O bandwidth is split up among all units within one slice relative to their block
I/O weight.</para>
<para>While <varname>StartupIOWeight=</varname> only applies
to the startup phase of the system,
@ -457,7 +458,7 @@
device of the file system of the file is determined. This controls the <literal>io.weight</literal> control
group attribute, which defaults to 100. Use this option multiple times to set weights for multiple devices.
For details about this control group attribute, see <ulink
url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>.</para>
url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html#io-interface-files">IO Interface Files</ulink>.</para>
<para>This setting replaces <varname>BlockIODeviceWeight=</varname> and disables settings prefixed with
<varname>BlockIO</varname> or <varname>StartupBlockIO</varname>.</para>
@ -479,7 +480,7 @@
"/dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0 5M"). This controls the <literal>io.max</literal> control
group attributes. Use this option multiple times to set bandwidth limits for multiple devices. For details
about this control group attribute, see <ulink
url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>.
url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html#io-interface-files">IO Interface Files</ulink>.
</para>
<para>These settings replace <varname>BlockIOReadBandwidth=</varname> and
@ -503,7 +504,7 @@
"/dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0 1K"). This controls the <literal>io.max</literal> control
group attributes. Use this option multiple times to set IOPS limits for multiple devices. For details about
this control group attribute, see <ulink
url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>.
url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html#io-interface-files">IO Interface Files</ulink>.
</para>
<para>These settings are supported only if the unified control group hierarchy is used and disable settings
@ -522,7 +523,7 @@
system of the file is determined. This controls the <literal>io.latency</literal> control group
attribute. Use this option multiple times to set latency target for multiple devices. For details about this
control group attribute, see <ulink
url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>.</para>
url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html#io-interface-files">IO Interface Files</ulink>.</para>
<para>Implies <literal>IOAccounting=yes</literal>.</para>
@ -697,8 +698,8 @@
(<emphasis>m</emphasis>knod), respectively. On cgroup-v1 this controls the
<literal>devices.allow</literal> control group attribute. For details about this control group
attribute, see <ulink
url="https://www.kernel.org/doc/Documentation/cgroup-v1/devices.txt">devices.txt</ulink>. On
cgroup-v2 this functionality is implemented using eBPF filtering.</para>
url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/devices.html">Device Whitelist Controller</ulink>.
In the unified cgroup hierarchy this functionality is implemented using eBPF filtering.</para>
<para>The device node specifier is either a path to a device node in the file system, starting with
<filename>/dev/</filename>, or a string starting with either <literal>char-</literal> or
@ -883,7 +884,7 @@ DeviceAllow=/dev/loop-control
<para>Assign the specified CPU time share weight to the processes executed. These options take an integer
value and control the <literal>cpu.shares</literal> control group attribute. The allowed range is 2 to
262144. Defaults to 1024. For details about this control group attribute, see <ulink
url="https://www.kernel.org/doc/Documentation/scheduler/sched-design-CFS.txt">sched-design-CFS.txt</ulink>.
url="https://www.kernel.org/doc/html/latest/scheduler/sched-design-CFS.html">CFS Scheduler</ulink>.
The available CPU time is split up among all units within one slice relative to their CPU time share
weight.</para>
@ -911,7 +912,7 @@ DeviceAllow=/dev/loop-control
<literal>infinity</literal>, no memory limit is applied. This controls the
<literal>memory.limit_in_bytes</literal> control group attribute. For details about this control group
attribute, see <ulink
url="https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt">memory.txt</ulink>.</para>
url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/memory.html">Memory Resource Controller</ulink>.</para>
<para>Implies <literal>MemoryAccounting=yes</literal>.</para>
@ -942,7 +943,7 @@ DeviceAllow=/dev/loop-control
group hierarchy is used on the system. Takes a single weight value (between 10 and 1000) to set the default
block I/O weight. This controls the <literal>blkio.weight</literal> control group attribute, which defaults to
500. For details about this control group attribute, see <ulink
url="https://www.kernel.org/doc/Documentation/cgroup-v1/blkio-controller.txt">blkio-controller.txt</ulink>.
url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/blkio-controller.html">Block IO Controller</ulink>.
The available I/O bandwidth is split up among all units within one slice relative to their block I/O
weight.</para>
@ -973,7 +974,7 @@ DeviceAllow=/dev/loop-control
file system of the file is determined. This controls the <literal>blkio.weight_device</literal> control group
attribute, which defaults to 1000. Use this option multiple times to set weights for multiple devices. For
details about this control group attribute, see <ulink
url="https://www.kernel.org/doc/Documentation/cgroup-v1/blkio-controller.txt">blkio-controller.txt</ulink>.</para>
url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/blkio-controller.html">Block IO Controller</ulink>.</para>
<para>Implies
<literal>BlockIOAccounting=yes</literal>.</para>
@ -997,7 +998,7 @@ DeviceAllow=/dev/loop-control
<literal>blkio.throttle.read_bps_device</literal> and <literal>blkio.throttle.write_bps_device</literal>
control group attributes. Use this option multiple times to set bandwidth limits for multiple devices. For
details about these control group attributes, see <ulink
url="https://www.kernel.org/doc/Documentation/cgroup-v1/blkio-controller.txt">blkio-controller.txt</ulink>.
url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/blkio-controller.html">Block IO Controller</ulink>.
</para>
<para>Implies
@ -1027,11 +1028,7 @@ DeviceAllow=/dev/loop-control
<citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
The documentation for control groups and specific controllers in the Linux kernel:
<ulink url="https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt">cgroups.txt</ulink>,
<ulink url="https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt">cpuacct.txt</ulink>,
<ulink url="https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt">memory.txt</ulink>,
<ulink url="https://www.kernel.org/doc/Documentation/cgroup-v1/blkio-controller.txt">blkio-controller.txt</ulink>.
<ulink url="https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt">sched-bwc.txt</ulink>.
<ulink url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html">Control Groups v2</ulink>.
</para>
</refsect1>
</refentry>

View File

@ -45,6 +45,15 @@
url="https://www.freedesktop.org/wiki/Software/systemd/ControlGroupInterface/">New
Control Group Interfaces</ulink> for an introduction on how to make
use of scope units from programs.</para>
<para>Note that unlike service units scope units have no "main" process, all processes in the scope are
equivalent. The lifecycle of the scope unit is thus not bound to the lifetime of one specific process but
to the existance of any processes in the scope. This also means that the exit status of these processes
do not cause the scope unit to enter a failure state. Scope units may still enter a failure state, for
example due to resource exhaustion or stop timeouts being reached, but not due to programs inside of them
terminating uncleanly. Since processes managed as scope units generally remain children of the original
process that forked them off it's also the job of that process to collect their exit statuses and act on
them as needed.</para>
</refsect1>
<refsect1>

View File

@ -873,7 +873,7 @@
<listitem><para>When specified without an argument or with a true argument,
enables the usage of
<ulink url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">unified cgroup hierarchy</ulink>
<ulink url="https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html">unified cgroup hierarchy</ulink>
(a.k.a. cgroups-v2). When specified with a false argument, fall back to
hybrid or full legacy cgroup hierarchy.</para>

View File

@ -1106,6 +1106,10 @@ const UnitVTable automount_vtable = {
"Automount\0"
"Install\0",
.can_transient = true,
.can_fail = true,
.can_trigger = true,
.init = automount_init,
.load = automount_load,
.done = automount_done,
@ -1132,8 +1136,6 @@ const UnitVTable automount_vtable = {
.bus_vtable = bus_automount_vtable,
.bus_set_property = bus_automount_set_property,
.can_transient = true,
.shutdown = automount_shutdown,
.supported = automount_supported,

View File

@ -651,30 +651,31 @@ static int lookup_block_device(const char *p, dev_t *ret) {
r = device_path_parse_major_minor(p, &mode, &rdev);
if (r == -ENODEV) { /* not a parsable device node, need to go to disk */
struct stat st;
if (stat(p, &st) < 0)
return log_warning_errno(errno, "Couldn't stat device '%s': %m", p);
rdev = (dev_t)st.st_rdev;
dev = (dev_t)st.st_dev;
mode = st.st_mode;
rdev = st.st_rdev;
dev = st.st_dev;
} else if (r < 0)
return log_warning_errno(r, "Failed to parse major/minor from path '%s': %m", p);
if (S_ISCHR(mode)) {
log_warning("Device node '%s' is a character device, but block device needed.", p);
return -ENOTBLK;
} else if (S_ISBLK(mode))
if (S_ISCHR(mode))
return log_warning_errno(SYNTHETIC_ERRNO(ENOTBLK),
"Device node '%s' is a character device, but block device needed.", p);
if (S_ISBLK(mode))
*ret = rdev;
else if (major(dev) != 0)
*ret = dev; /* If this is not a device node then use the block device this file is stored on */
else {
/* If this is btrfs, getting the backing block device is a bit harder */
r = btrfs_get_block_device(p, ret);
if (r < 0 && r != -ENOTTY)
if (r == -ENOTTY)
return log_warning_errno(SYNTHETIC_ERRNO(ENODEV),
"'%s' is not a block device node, and file system block device cannot be determined or is not local.", p);
if (r < 0)
return log_warning_errno(r, "Failed to determine block device backing btrfs file system '%s': %m", p);
if (r == -ENOTTY) {
log_warning("'%s' is not a block device node, and file system block device cannot be determined or is not local.", p);
return -ENODEV;
}
}
/* If this is a LUKS device, try to get the originating block device */
@ -1526,11 +1527,10 @@ CGroupMask unit_get_members_mask(Unit *u) {
Unit *member;
Iterator i;
HASHMAP_FOREACH_KEY(v, member, u->dependencies[UNIT_BEFORE], i) {
HASHMAP_FOREACH_KEY(v, member, u->dependencies[UNIT_BEFORE], i)
if (UNIT_DEREF(member->slice) == u)
u->cgroup_members_mask |= unit_get_subtree_mask(member); /* note that this calls ourselves again, for the children */
}
}
u->cgroup_members_mask_valid = true;
return u->cgroup_members_mask;
@ -2335,7 +2335,15 @@ static void unit_add_siblings_to_cgroup_realize_queue(Unit *u) {
Unit *slice;
/* This adds the siblings of the specified unit and the siblings of all parent units to the cgroup
* queue. (But neither the specified unit itself nor the parents.) */
* queue. (But neither the specified unit itself nor the parents.)
*
* Propagation of realization "side-ways" (i.e. towards siblings) is relevant on cgroup-v1 where
* scheduling becomes very weird if two units that own processes reside in the same slice, but one is
* realized in the "cpu" hierarchy and one is not (for example because one has CPUWeight= set and the
* other does not), because that means individual processes need to be scheduled against whole
* cgroups. Let's avoid this asymmetry by always ensuring that units below a slice that are realized
* at all are always realized in *all* their hierarchies, and it is sufficient for a unit's sibling
* to be realized for the unit itself to be realized too. */
while ((slice = UNIT_DEREF(u->slice))) {
Iterator i;
@ -2343,6 +2351,7 @@ static void unit_add_siblings_to_cgroup_realize_queue(Unit *u) {
void *v;
HASHMAP_FOREACH_KEY(v, m, slice->dependencies[UNIT_BEFORE], i) {
/* Skip units that have a dependency on the slice but aren't actually in it. */
if (UNIT_DEREF(m->slice) != slice)
continue;
@ -2351,6 +2360,11 @@ static void unit_add_siblings_to_cgroup_realize_queue(Unit *u) {
if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(m)))
continue;
/* We only enqueue siblings if they were realized once at least, in the main
* hierarchy. */
if (!m->cgroup_realized)
continue;
/* If the unit doesn't need any new controllers and has current ones realized, it
* doesn't need any changes. */
if (unit_has_mask_realized(m,
@ -2648,6 +2662,7 @@ void unit_add_to_cgroup_empty_queue(Unit *u) {
/* Let's verify that the cgroup is really empty */
if (!u->cgroup_path)
return;
r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
if (r < 0) {
log_unit_debug_errno(u, r, "Failed to determine whether cgroup %s is empty: %m", u->cgroup_path);
@ -3512,11 +3527,10 @@ void unit_invalidate_cgroup_bpf(Unit *u) {
Iterator i;
void *v;
HASHMAP_FOREACH_KEY(v, member, u->dependencies[UNIT_BEFORE], i) {
HASHMAP_FOREACH_KEY(v, member, u->dependencies[UNIT_BEFORE], i)
if (UNIT_DEREF(member->slice) == u)
unit_invalidate_cgroup_bpf(member);
}
}
}
bool unit_cgroup_delegate(Unit *u) {
@ -3607,7 +3621,7 @@ int unit_get_cpuset(Unit *u, CPUSet *cpus, const char *name) {
return r;
if (r == 0)
return -ENODATA;
if (r > 0)
r = cg_get_attribute("cpuset", u->cgroup_path, name, &v);
if (r == -ENOENT)
return -ENODATA;

View File

@ -1064,6 +1064,7 @@ const UnitVTable device_vtable = {
"Device\0"
"Install\0",
.refuse_after = true,
.gc_jobs = true,
.init = device_init,

View File

@ -2589,7 +2589,7 @@ static int apply_mount_namespace(
needs_sandboxing ? context->protect_home : PROTECT_HOME_NO,
needs_sandboxing ? context->protect_system : PROTECT_SYSTEM_NO,
context->mount_flags,
DISSECT_IMAGE_DISCARD_ON_LOOP,
DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK,
error_path);
/* If we couldn't set up the namespace this is probably due to a missing capability. setup_namespace() reports

View File

@ -2065,6 +2065,9 @@ const UnitVTable mount_vtable = {
"Install\0",
.private_section = "Mount",
.can_transient = true,
.can_fail = true,
.init = mount_init,
.load = mount_load,
.done = mount_done,
@ -2103,8 +2106,6 @@ const UnitVTable mount_vtable = {
.get_timeout = mount_get_timeout,
.can_transient = true,
.enumerate_perpetual = mount_enumerate_perpetual,
.enumerate = mount_enumerate,
.shutdown = mount_shutdown,

View File

@ -806,6 +806,8 @@ const UnitVTable path_vtable = {
.private_section = "Path",
.can_transient = true,
.can_fail = true,
.can_trigger = true,
.init = path_init,
.done = path_done,

View File

@ -619,6 +619,7 @@ const UnitVTable scope_vtable = {
.can_transient = true,
.can_delegate = true,
.can_fail = true,
.once_only = true,
.init = scope_init,

View File

@ -4391,6 +4391,7 @@ const UnitVTable service_vtable = {
.can_transient = true,
.can_delegate = true,
.can_fail = true,
.init = service_init,
.done = service_done,

View File

@ -3423,6 +3423,8 @@ const UnitVTable socket_vtable = {
.private_section = "Socket",
.can_transient = true,
.can_trigger = true,
.can_fail = true,
.init = socket_init,
.done = socket_done,

View File

@ -1590,6 +1590,8 @@ const UnitVTable swap_vtable = {
"Install\0",
.private_section = "Swap",
.can_fail = true,
.init = swap_init,
.load = swap_load,
.done = swap_done,

View File

@ -895,6 +895,10 @@ const UnitVTable timer_vtable = {
"Install\0",
.private_section = "Timer",
.can_transient = true,
.can_fail = true,
.can_trigger = true,
.init = timer_init,
.done = timer_done,
.load = timer_load,
@ -923,6 +927,4 @@ const UnitVTable timer_vtable = {
.bus_vtable = bus_timer_vtable,
.bus_set_property = bus_timer_set_property,
.can_transient = true,
};

View File

@ -2937,12 +2937,28 @@ int unit_add_dependency(
return 0;
}
if ((d == UNIT_BEFORE && other->type == UNIT_DEVICE) ||
(d == UNIT_AFTER && u->type == UNIT_DEVICE)) {
log_unit_warning(u, "Dependency Before=%s ignored (.device units cannot be delayed)", other->id);
if (d == UNIT_AFTER && UNIT_VTABLE(u)->refuse_after) {
log_unit_warning(u, "Requested dependency After=%s ignored (%s units cannot be delayed).", other->id, unit_type_to_string(u->type));
return 0;
}
if (d == UNIT_BEFORE && UNIT_VTABLE(other)->refuse_after) {
log_unit_warning(u, "Requested dependency Before=%s ignored (%s units cannot be delayed).", other->id, unit_type_to_string(other->type));
return 0;
}
if (d == UNIT_ON_FAILURE && !UNIT_VTABLE(u)->can_fail) {
log_unit_warning(u, "Requested dependency OnFailure=%s ignored (%s units cannot fail).", other->id, unit_type_to_string(u->type));
return 0;
}
if (d == UNIT_TRIGGERS && !UNIT_VTABLE(u)->can_trigger)
return log_unit_error_errno(u, SYNTHETIC_ERRNO(EINVAL),
"Requested dependency Triggers=%s refused (%s units cannot trigger other units).", other->id, unit_type_to_string(u->type));
if (d == UNIT_TRIGGERED_BY && !UNIT_VTABLE(other)->can_trigger)
return log_unit_error_errno(u, SYNTHETIC_ERRNO(EINVAL),
"Requested dependency TriggeredBy=%s refused (%s units cannot trigger other units).", other->id, unit_type_to_string(other->type));
r = unit_add_dependency_hashmap(u->dependencies + d, other, mask, 0);
if (r < 0)
return r;

View File

@ -600,6 +600,15 @@ typedef struct UnitVTable {
/* True if cgroup delegation is permissible */
bool can_delegate:1;
/* True if the unit type triggers other units, i.e. can have a UNIT_TRIGGERS dependency */
bool can_trigger:1;
/* True if the unit type knows a failure state, and thus can be source of an OnFailure= dependency */
bool can_fail:1;
/* True if After= dependencies should be refused */
bool refuse_after:1;
/* True if units of this type shall be startable only once and then never again */
bool once_only:1;

View File

@ -22,7 +22,7 @@ static enum {
} arg_action = ACTION_DISSECT;
static const char *arg_image = NULL;
static const char *arg_path = NULL;
static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP;
static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK;
static void *arg_root_hash = NULL;
static size_t arg_root_hash_size = 0;

View File

@ -710,6 +710,18 @@ static int enumerate_partitions(dev_t devnum) {
r = k;
}
if (m->partitions[PARTITION_VAR].found) {
k = add_partition_mount(m->partitions + PARTITION_VAR, "var", "/var", "Variable Data Partition");
if (k < 0)
r = k;
}
if (m->partitions[PARTITION_TMP].found) {
k = add_partition_mount(m->partitions + PARTITION_TMP, "var-tmp", "/var/tmp", "Temporary Data Partition");
if (k < 0)
r = k;
}
if (m->partitions[PARTITION_ROOT].found) {
k = add_root_rw(m->partitions + PARTITION_ROOT);
if (k < 0)

View File

@ -249,7 +249,11 @@ static int method_set_idle_hint(sd_bus_message *message, void *userdata, sd_bus_
if (uid != 0 && uid != s->user->uid)
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set idle hint");
session_set_idle_hint(s, b);
r = session_set_idle_hint(s, b);
if (r == -ENOTTY)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Idle hint control is not supported on non-graphical sessions.");
if (r < 0)
return r;
return sd_bus_reply_method_return(message, NULL);
}

View File

@ -932,63 +932,57 @@ static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
}
int session_get_idle_hint(Session *s, dual_timestamp *t) {
usec_t atime = 0, n;
usec_t atime = 0;
int r;
assert(s);
/* Explicit idle hint is set */
if (s->idle_hint) {
/* Graphical sessions have an explicit idle hint */
if (SESSION_TYPE_IS_GRAPHICAL(s->type)) {
if (t)
*t = s->idle_hint_timestamp;
return s->idle_hint;
}
/* Graphical sessions should really implement a real
* idle hint logic */
if (SESSION_TYPE_IS_GRAPHICAL(s->type))
goto dont_know;
/* For sessions with an explicitly configured tty, let's check
* its atime */
/* For sessions with an explicitly configured tty, let's check its atime */
if (s->tty) {
r = get_tty_atime(s->tty, &atime);
if (r >= 0)
goto found_atime;
}
/* For sessions with a leader but no explicitly configured
* tty, let's check the controlling tty of the leader */
/* For sessions with a leader but no explicitly configured tty, let's check the controlling tty of
* the leader */
if (pid_is_valid(s->leader)) {
r = get_process_ctty_atime(s->leader, &atime);
if (r >= 0)
goto found_atime;
}
dont_know:
if (t)
*t = s->idle_hint_timestamp;
*t = DUAL_TIMESTAMP_NULL;
return 0;
return false;
found_atime:
if (t)
dual_timestamp_from_realtime(t, atime);
n = now(CLOCK_REALTIME);
if (s->manager->idle_action_usec <= 0)
return 0;
return false;
return atime + s->manager->idle_action_usec <= n;
return usec_add(atime, s->manager->idle_action_usec) <= now(CLOCK_REALTIME);
}
void session_set_idle_hint(Session *s, bool b) {
int session_set_idle_hint(Session *s, bool b) {
assert(s);
if (!SESSION_TYPE_IS_GRAPHICAL(s->type))
return -ENOTTY;
if (s->idle_hint == b)
return;
return 0;
s->idle_hint = b;
dual_timestamp_get(&s->idle_hint_timestamp);
@ -1000,6 +994,8 @@ void session_set_idle_hint(Session *s, bool b) {
user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
return 1;
}
int session_get_locked_hint(Session *s) {

View File

@ -132,7 +132,7 @@ void session_add_to_gc_queue(Session *s);
int session_activate(Session *s);
bool session_is_active(Session *s);
int session_get_idle_hint(Session *s, dual_timestamp *t);
void session_set_idle_hint(Session *s, bool b);
int session_set_idle_hint(Session *s, bool b);
int session_get_locked_hint(Session *s);
void session_set_locked_hint(Session *s, bool b);
int session_create_fifo(Session *s);

View File

@ -5112,14 +5112,14 @@ static int run(int argc, char *argv[]) {
loop->fd,
arg_image,
arg_root_hash, arg_root_hash_size,
DISSECT_IMAGE_REQUIRE_ROOT,
DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK,
&dissected_image);
if (r == -ENOPKG) {
/* dissected_image_and_warn() already printed a brief error message. Extend on that with more details */
log_notice("Note that the disk image needs to\n"
" a) either contain only a single MBR partition of type 0x83 that is marked bootable\n"
" b) or contain a single GPT partition of type 0FC63DAF-8483-4772-8E79-3D69D8477DE4\n"
" c) or follow http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/\n"
" c) or follow https://systemd.io/DISCOVERABLE_PARTITIONS\n"
" d) or contain a file system without a partition table\n"
"in order to be bootable with systemd-nspawn.");
goto finish;

View File

@ -387,7 +387,7 @@ static int portable_extract_by_path(
if (r < 0)
return log_debug_errno(r, "Failed to create temporary directory: %m");
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP, &m);
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
if (r == -ENOPKG)
sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Couldn't identify a suitable partition table or file system in '%s'.", path);
else if (r == -EADDRNOTAVAIL)

View File

@ -598,6 +598,43 @@ int dissect_image(
if (!generic_node)
return -ENOMEM;
}
} else if (sd_id128_equal(type_id, GPT_TMP)) {
if (pflags & GPT_FLAG_NO_AUTO)
continue;
designator = PARTITION_TMP;
rw = !(pflags & GPT_FLAG_READ_ONLY);
} else if (sd_id128_equal(type_id, GPT_VAR)) {
if (pflags & GPT_FLAG_NO_AUTO)
continue;
if (!FLAGS_SET(flags, DISSECT_IMAGE_RELAX_VAR_CHECK)) {
sd_id128_t var_uuid;
/* For /var we insist that the uuid of the partition matches the
* HMAC-SHA256 of the /var GPT partition type uuid, keyed by machine
* ID. Why? Unlike the other partitions /var is inherently
* installation specific, hence we need to be careful not to mount it
* in the wrong installation. By hashing the partition UUID from
* /etc/machine-id we can securely bind the partition to the
* installation. */
r = sd_id128_get_machine_app_specific(GPT_VAR, &var_uuid);
if (r < 0)
return r;
if (!sd_id128_equal(var_uuid, id)) {
log_debug("Found a /var/ partition, but its UUID didn't match our expectations, ignoring.");
continue;
}
}
designator = PARTITION_VAR;
rw = !(pflags & GPT_FLAG_READ_ONLY);
}
if (designator != _PARTITION_DESIGNATOR_INVALID) {
@ -910,6 +947,14 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift,
if (r < 0)
return r;
r = mount_partition(m->partitions + PARTITION_VAR, where, "/var", uid_shift, flags);
if (r < 0)
return r;
r = mount_partition(m->partitions + PARTITION_TMP, where, "/var/tmp", uid_shift, flags);
if (r < 0)
return r;
boot_mounted = mount_partition(m->partitions + PARTITION_XBOOTLDR, where, "/boot", uid_shift, flags);
if (boot_mounted < 0)
return boot_mounted;
@ -1333,7 +1378,8 @@ int dissected_image_acquire_metadata(DissectedImage *m) {
[META_HOSTNAME] = "/etc/hostname\0",
[META_MACHINE_ID] = "/etc/machine-id\0",
[META_MACHINE_INFO] = "/etc/machine-info\0",
[META_OS_RELEASE] = "/etc/os-release\0/usr/lib/os-release\0",
[META_OS_RELEASE] = "/etc/os-release\0"
"/usr/lib/os-release\0",
};
_cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL;
@ -1528,6 +1574,8 @@ static const char *const partition_designator_table[] = {
[PARTITION_SWAP] = "swap",
[PARTITION_ROOT_VERITY] = "root-verity",
[PARTITION_ROOT_SECONDARY_VERITY] = "root-secondary-verity",
[PARTITION_TMP] = "tmp",
[PARTITION_VAR] = "var",
};
DEFINE_STRING_TABLE_LOOKUP(partition_designator, int);

View File

@ -33,6 +33,8 @@ enum {
PARTITION_SWAP,
PARTITION_ROOT_VERITY, /* verity data for the PARTITION_ROOT partition */
PARTITION_ROOT_SECONDARY_VERITY, /* verity data for the PARTITION_ROOT_SECONDARY partition */
PARTITION_TMP,
PARTITION_VAR,
_PARTITION_DESIGNATOR_MAX,
_PARTITION_DESIGNATOR_INVALID = -1
};
@ -59,6 +61,7 @@ typedef enum DissectImageFlags {
DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY = 1 << 7, /* Mount only non-root partitions */
DISSECT_IMAGE_VALIDATE_OS = 1 << 8, /* Refuse mounting images that aren't identifiable as OS images */
DISSECT_IMAGE_NO_UDEV = 1 << 9, /* Don't wait for udev initializing things */
DISSECT_IMAGE_RELAX_VAR_CHECK = 1 << 10, /* Don't insist that the UUID of /var is hashed from /etc/machine-id */
} DissectImageFlags;
struct DissectedImage {

View File

@ -19,6 +19,8 @@
#define GPT_SWAP SD_ID128_MAKE(06,57,fd,6d,a4,ab,43,c4,84,e5,09,33,c8,4b,4f,4f)
#define GPT_HOME SD_ID128_MAKE(93,3a,c7,e1,2e,b4,4f,13,b8,44,0e,14,e2,ae,f9,15)
#define GPT_SRV SD_ID128_MAKE(3b,8f,84,25,20,e0,4f,3b,90,7f,1a,25,a7,6f,98,e8)
#define GPT_VAR SD_ID128_MAKE(4d,21,b0,16,b5,34,45,c2,a9,fb,5c,16,e0,91,fd,2d)
#define GPT_TMP SD_ID128_MAKE(7e,c6,f5,57,3b,c5,4a,ca,b2,93,16,ef,5d,f6,39,d1)
/* Verity partitions for the root partitions above (we only define them for the root partitions, because only they are
* are commonly read-only and hence suitable for verity). */

View File

@ -1171,7 +1171,7 @@ int image_read_metadata(Image *i) {
if (r < 0)
return r;
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT, &m);
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
if (r < 0)
return r;

View File

@ -39,6 +39,7 @@
#include "exec-util.h"
#include "exit-status.h"
#include "fd-util.h"
#include "format-table.h"
#include "format-util.h"
#include "fs-util.h"
#include "glob-util.h"
@ -389,122 +390,42 @@ static bool output_show_unit(const UnitInfo *u, char **patterns) {
}
static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
unsigned circle_len = 0, id_len, max_id_len, load_len, active_len, sub_len, job_len, desc_len, max_desc_len;
_cleanup_(table_unrefp) Table *table = NULL;
const UnitInfo *u;
unsigned n_shown = 0;
int job_count = 0;
bool full = arg_full || FLAGS_SET(arg_pager_flags, PAGER_DISABLE);
int r;
max_id_len = STRLEN("UNIT");
load_len = STRLEN("LOAD");
active_len = STRLEN("ACTIVE");
sub_len = STRLEN("SUB");
job_len = STRLEN("JOB");
max_desc_len = STRLEN("DESCRIPTION");
table = table_new("", "unit", "load", "active", "sub", "job", "description");
if (!table)
return log_oom();
table_set_header(table, !arg_no_legend);
if (arg_full)
table_set_width(table, 0);
for (u = unit_infos; u < unit_infos + c; u++) {
max_id_len = MAX(max_id_len, strlen(u->id) + (u->machine ? strlen(u->machine)+1 : 0));
load_len = MAX(load_len, strlen(u->load_state));
active_len = MAX(active_len, strlen(u->active_state));
sub_len = MAX(sub_len, strlen(u->sub_state));
max_desc_len = MAX(max_desc_len, strlen(u->description));
if (u->job_id != 0) {
job_len = MAX(job_len, strlen(u->job_type));
job_count++;
}
if (!arg_no_legend &&
(streq(u->active_state, "failed") ||
STR_IN_SET(u->load_state, "error", "not-found", "bad-setting", "masked")))
circle_len = 2;
}
if (!arg_full && original_stdout_is_tty) {
unsigned basic_len;
id_len = MIN(max_id_len, 25u); /* as much as it needs, but at most 25 for now */
basic_len = circle_len + 1 + id_len + 1 + load_len + 1 + active_len + 1 + sub_len + 1;
if (job_count)
basic_len += job_len + 1;
if (basic_len < (unsigned) columns()) {
unsigned extra_len, incr;
extra_len = columns() - basic_len;
/* Either UNIT already got 25, or is fully satisfied.
* Grant up to 25 to DESC now. */
incr = MIN(extra_len, 25u);
desc_len = incr;
extra_len -= incr;
/* Of the remainder give as much as the ID needs to the ID, and give the rest to the
* description but not more than it needs. */
if (extra_len > 0) {
incr = MIN(max_id_len - id_len, extra_len);
id_len += incr;
desc_len += MIN(extra_len - incr, max_desc_len - desc_len);
}
} else
desc_len = 0;
} else {
id_len = max_id_len;
desc_len = max_desc_len;
}
for (u = unit_infos; u < unit_infos + c; u++) {
_cleanup_free_ char *e = NULL, *j = NULL;
const char *on_underline = "", *off_underline = "";
const char *on_loaded = "", *off_loaded = "";
const char *on_active = "", *off_active = "";
const char *on_circle = "", *off_circle = "";
const char *id;
_cleanup_free_ char *j = NULL;
const char *on_underline = "", *on_loaded = "", *on_active = "";
const char *on_circle = "", *id;
bool circle = false, underline = false;
if (!n_shown && !arg_no_legend) {
if (circle_len > 0)
fputs(" ", stdout);
printf("%s%-*s %-*s %-*s %-*s ",
ansi_underline(),
id_len, "UNIT",
load_len, "LOAD",
active_len, "ACTIVE",
sub_len, "SUB");
if (job_count)
printf("%-*s ", job_len, "JOB");
printf("%-*.*s%s\n",
desc_len,
full ? -1 : (int) desc_len,
"DESCRIPTION",
ansi_normal());
}
n_shown++;
if (u + 1 < unit_infos + c &&
!streq(unit_type_suffix(u->id), unit_type_suffix((u + 1)->id))) {
on_underline = ansi_underline();
off_underline = ansi_normal();
underline = true;
}
if (STR_IN_SET(u->load_state, "error", "not-found", "bad-setting", "masked") && !arg_plain) {
on_circle = ansi_highlight_yellow();
off_circle = ansi_normal();
circle = true;
on_loaded = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
off_loaded = underline ? on_underline : ansi_normal();
} else if (streq(u->active_state, "failed") && !arg_plain) {
on_circle = ansi_highlight_red();
off_circle = ansi_normal();
circle = true;
on_active = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
off_active = underline ? on_underline : ansi_normal();
} else {
on_active = on_underline;
on_loaded = on_underline;
}
if (u->machine) {
@ -516,36 +437,47 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
} else
id = u->id;
if (arg_full) {
e = ellipsize(id, id_len, 33);
if (!e)
return log_oom();
r = table_add_many(table,
TABLE_STRING, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ",
TABLE_SET_COLOR, on_circle,
TABLE_STRING, id,
TABLE_SET_COLOR, on_active,
TABLE_STRING, u->load_state,
TABLE_SET_COLOR, on_loaded,
TABLE_STRING, u->active_state,
TABLE_SET_COLOR, on_active,
TABLE_STRING, u->sub_state,
TABLE_SET_COLOR, on_active,
TABLE_STRING, u->job_id ? u->job_type: "",
TABLE_SET_COLOR, u->job_id ? on_underline : "",
TABLE_STRING, u->description,
TABLE_SET_COLOR, on_underline);
if (r < 0)
return table_log_add_error(r);
id = e;
if (u->job_id != 0)
job_count++;
}
if (circle_len > 0)
printf("%s%s%s ", on_circle, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ", off_circle);
printf("%s%s%-*s%s %s%-*s%s %s%-*s %-*s%s %-*s",
on_underline,
on_active, id_len, id, off_active,
on_loaded, load_len, u->load_state, off_loaded,
on_active, active_len, u->active_state,
sub_len, u->sub_state, off_active,
job_count ? job_len + 1 : 0, u->job_id ? u->job_type : "");
printf("%-*.*s%s\n",
desc_len,
full ? -1 : (int) desc_len,
u->description,
off_underline);
if (job_count == 0) {
/* There's no data in the JOB column, so let's hide it */
/* Also, convert all number constants to size_t so va_arg()
* in table_set_display() fetches a correct number of bytes from
* the stack */
r = table_set_display(table, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 4, (size_t) 6, (size_t) -1);
if (r < 0)
return log_error_errno(r, "Failed to set columns to display: %m");
}
r = table_print(table, NULL);
if (r < 0)
return log_error_errno(r, "Failed to print the table: %m");
if (!arg_no_legend) {
const char *on, *off;
size_t records = table_get_rows(table) - 1;
if (n_shown) {
if (records > 0) {
puts("\n"
"LOAD = Reflects whether the unit definition was properly loaded.\n"
"ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
@ -559,15 +491,15 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
}
if (arg_all || strv_contains(arg_states, "inactive"))
printf("%s%u loaded units listed.%s\n"
printf("%s%zu loaded units listed.%s\n"
"To show all installed unit files use 'systemctl list-unit-files'.\n",
on, n_shown, off);
on, records, off);
else if (!arg_states)
printf("%s%u loaded units listed.%s Pass --all to see loaded but inactive units, too.\n"
printf("%s%zu loaded units listed.%s Pass --all to see loaded but inactive units, too.\n"
"To show all installed unit files use 'systemctl list-unit-files'.\n",
on, n_shown, off);
on, records, off);
else
printf("%u loaded units listed.\n", n_shown);
printf("%zu loaded units listed.\n", records);
}
return 0;
@ -1048,39 +980,30 @@ static int socket_info_compare(const struct socket_info *a, const struct socket_
}
static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
_cleanup_(table_unrefp) Table *table = NULL;
struct socket_info *s;
unsigned pathlen = STRLEN("LISTEN"),
typelen = STRLEN("TYPE") * arg_show_types,
socklen = STRLEN("UNIT"),
servlen = STRLEN("ACTIVATES");
const char *on, *off;
int r;
for (s = socket_infos; s < socket_infos + cs; s++) {
unsigned tmp = 0;
char **a;
table = table_new("listen", "type", "units", "activates");
if (!table)
return log_oom();
socklen = MAX(socklen, strlen(s->id));
if (arg_show_types)
typelen = MAX(typelen, strlen(s->type));
pathlen = MAX(pathlen, strlen(s->path) + (s->machine ? strlen(s->machine)+1 : 0));
STRV_FOREACH(a, s->triggered)
tmp += strlen(*a) + 2*(a != s->triggered);
servlen = MAX(servlen, tmp);
if (!arg_show_types) {
/* Hide the second (TYPE) column */
r = table_set_display(table, 0, 2, 3, (size_t) -1);
if (r < 0)
return log_error_errno(r, "Failed to set columns to display: %m");
}
if (cs) {
if (!arg_no_legend)
printf("%-*s %-*.*s%-*s %s\n",
pathlen, "LISTEN",
typelen + arg_show_types, typelen + arg_show_types, "TYPE ",
socklen, "UNIT",
"ACTIVATES");
table_set_header(table, !arg_no_legend);
if (arg_full)
table_set_width(table, 0);
if (cs) {
for (s = socket_infos; s < socket_infos + cs; s++) {
_cleanup_free_ char *j = NULL;
_cleanup_free_ char *j = NULL, *activates = NULL;
const char *path;
char **a;
if (s->machine) {
j = strjoin(s->machine, ":", s->path);
@ -1090,29 +1013,32 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
} else
path = s->path;
if (arg_show_types)
printf("%-*s %-*s %-*s",
pathlen, path, typelen, s->type, socklen, s->id);
else
printf("%-*s %-*s",
pathlen, path, socklen, s->id);
STRV_FOREACH(a, s->triggered)
printf("%s %s",
a == s->triggered ? "" : ",", *a);
printf("\n");
activates = strv_join(s->triggered, ", ");
if (!activates)
return log_oom();
r = table_add_many(table,
TABLE_STRING, path,
TABLE_STRING, s->type,
TABLE_STRING, s->id,
TABLE_STRING, activates);
if (r < 0)
return table_log_add_error(r);
}
on = ansi_highlight();
off = ansi_normal();
if (!arg_no_legend)
printf("\n");
} else {
on = ansi_highlight_red();
off = ansi_normal();
}
r = table_print(table, NULL);
if (r < 0)
return log_error_errno(r, "Failed to print the table: %m");
if (!arg_no_legend) {
printf("%s%u sockets listed.%s\n", on, cs, off);
printf("\n%s%u sockets listed.%s\n", on, cs, off);
if (!arg_all)
printf("Pass --all to see loaded but inactive sockets, too.\n");
}
@ -1303,73 +1229,25 @@ static int timer_info_compare(const struct timer_info *a, const struct timer_inf
}
static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
_cleanup_(table_unrefp) Table *table = NULL;
struct timer_info *t;
unsigned
nextlen = STRLEN("NEXT"),
leftlen = STRLEN("LEFT"),
lastlen = STRLEN("LAST"),
passedlen = STRLEN("PASSED"),
unitlen = STRLEN("UNIT"),
activatelen = STRLEN("ACTIVATES");
const char *on, *off;
int r;
assert(timer_infos || n == 0);
for (t = timer_infos; t < timer_infos + n; t++) {
unsigned ul = 0;
char **a;
table = table_new("next", "left", "last", "passed", "unit", "activates");
if (!table)
return log_oom();
if (t->next_elapse > 0) {
char tstamp[FORMAT_TIMESTAMP_MAX] = "", trel[FORMAT_TIMESTAMP_RELATIVE_MAX] = "";
format_timestamp(tstamp, sizeof(tstamp), t->next_elapse);
nextlen = MAX(nextlen, strlen(tstamp) + 1);
format_timestamp_relative(trel, sizeof(trel), t->next_elapse);
leftlen = MAX(leftlen, strlen(trel));
}
if (t->last_trigger > 0) {
char tstamp[FORMAT_TIMESTAMP_MAX] = "", trel[FORMAT_TIMESTAMP_RELATIVE_MAX] = "";
format_timestamp(tstamp, sizeof(tstamp), t->last_trigger);
lastlen = MAX(lastlen, strlen(tstamp) + 1);
format_timestamp_relative(trel, sizeof(trel), t->last_trigger);
passedlen = MAX(passedlen, strlen(trel));
}
unitlen = MAX(unitlen, strlen(t->id) + (t->machine ? strlen(t->machine)+1 : 0));
STRV_FOREACH(a, t->triggered)
ul += strlen(*a) + 2*(a != t->triggered);
activatelen = MAX(activatelen, ul);
}
table_set_header(table, !arg_no_legend);
if (arg_full)
table_set_width(table, 0);
if (n > 0) {
if (!arg_no_legend)
printf("%-*s %-*s %-*s %-*s %-*s %s\n",
nextlen, "NEXT",
leftlen, "LEFT",
lastlen, "LAST",
passedlen, "PASSED",
unitlen, "UNIT",
"ACTIVATES");
for (t = timer_infos; t < timer_infos + n; t++) {
_cleanup_free_ char *j = NULL;
_cleanup_free_ char *j = NULL, *activates = NULL;
const char *unit;
char tstamp1[FORMAT_TIMESTAMP_MAX] = "n/a", trel1[FORMAT_TIMESTAMP_RELATIVE_MAX] = "n/a";
char tstamp2[FORMAT_TIMESTAMP_MAX] = "n/a", trel2[FORMAT_TIMESTAMP_RELATIVE_MAX] = "n/a";
char **a;
format_timestamp(tstamp1, sizeof(tstamp1), t->next_elapse);
format_timestamp_relative(trel1, sizeof(trel1), t->next_elapse);
format_timestamp(tstamp2, sizeof(tstamp2), t->last_trigger);
format_timestamp_relative(trel2, sizeof(trel2), t->last_trigger);
if (t->machine) {
j = strjoin(t->machine, ":", t->id);
@ -1379,26 +1257,34 @@ static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
} else
unit = t->id;
printf("%-*s %-*s %-*s %-*s %-*s",
nextlen, tstamp1, leftlen, trel1, lastlen, tstamp2, passedlen, trel2, unitlen, unit);
activates = strv_join(t->triggered, ", ");
if (!activates)
return log_oom();
STRV_FOREACH(a, t->triggered)
printf("%s %s",
a == t->triggered ? "" : ",", *a);
printf("\n");
r = table_add_many(table,
TABLE_TIMESTAMP, t->next_elapse,
TABLE_TIMESTAMP_RELATIVE, t->next_elapse,
TABLE_TIMESTAMP, t->last_trigger,
TABLE_TIMESTAMP_RELATIVE, t->last_trigger,
TABLE_STRING, unit,
TABLE_STRING, activates);
if (r < 0)
return table_log_add_error(r);
}
on = ansi_highlight();
off = ansi_normal();
if (!arg_no_legend)
printf("\n");
} else {
on = ansi_highlight_red();
off = ansi_normal();
}
r = table_print(table, NULL);
if (r < 0)
return log_error_errno(r, "Failed to print the table: %m");
if (!arg_no_legend) {
printf("%s%u timers listed.%s\n", on, n, off);
printf("\n%s%u timers listed.%s\n", on, n, off);
if (!arg_all)
printf("Pass --all to see loaded but inactive timers, too.\n");
}
@ -1549,42 +1435,22 @@ static bool output_show_unit_file(const UnitFileList *u, char **states, char **p
return true;
}
static void output_unit_file_list(const UnitFileList *units, unsigned c) {
unsigned max_id_len, id_cols, state_cols, preset_cols;
static int output_unit_file_list(const UnitFileList *units, unsigned c) {
_cleanup_(table_unrefp) Table *table = NULL;
const UnitFileList *u;
int r;
max_id_len = STRLEN("UNIT FILE");
state_cols = STRLEN("STATE");
preset_cols = STRLEN("VENDOR PRESET");
table = table_new("unit file", "state", "vendor preset");
if (!table)
return log_oom();
for (u = units; u < units + c; u++) {
max_id_len = MAX(max_id_len, strlen(basename(u->path)));
state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state)));
}
if (!arg_full) {
unsigned basic_cols;
id_cols = MIN(max_id_len, 25u);
basic_cols = 1 + id_cols + state_cols;
if (basic_cols < (unsigned) columns())
id_cols += MIN(columns() - basic_cols, max_id_len - id_cols);
} else
id_cols = max_id_len;
if (!arg_no_legend && c > 0)
printf("%s%-*s %-*s %-*s%s\n",
ansi_underline(),
id_cols, "UNIT FILE",
state_cols, "STATE",
preset_cols, "VENDOR PRESET",
ansi_normal());
table_set_header(table, !arg_no_legend);
if (arg_full)
table_set_width(table, 0);
for (u = units; u < units + c; u++) {
const char *on_underline = NULL, *on_unit_color = NULL, *id;
const char *on_preset_color = NULL, *off_preset = NULL, *unit_preset_str;
_cleanup_free_ char *e = NULL;
int r;
const char *on_preset_color = NULL, *unit_preset_str;
bool underline;
underline = u + 1 < units + c &&
@ -1601,6 +1467,8 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
on_unit_color = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
else if (u->state == UNIT_FILE_ENABLED)
on_unit_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
else
on_unit_color = on_underline;
id = basename(u->path);
@ -1616,20 +1484,25 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
on_preset_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
}
if (on_underline || on_preset_color)
off_preset = ansi_normal();
e = arg_full ? NULL : ellipsize(id, id_cols, 33);
printf("%s%-*s %s%-*s %s%-*s%s\n",
strempty(on_underline),
id_cols, e ? e : id,
strempty(on_unit_color), state_cols, unit_file_state_to_string(u->state),
strempty(on_preset_color), preset_cols, unit_preset_str, strempty(off_preset));
r = table_add_many(table,
TABLE_STRING, id,
TABLE_SET_COLOR, strempty(on_underline),
TABLE_STRING, unit_file_state_to_string(u->state),
TABLE_SET_COLOR, strempty(on_unit_color),
TABLE_STRING, unit_preset_str,
TABLE_SET_COLOR, strempty(on_preset_color));
if (r < 0)
return table_log_add_error(r);
}
r = table_print(table, NULL);
if (r < 0)
return log_error_errno(r, "Failed to print the table: %m");
if (!arg_no_legend)
printf("\n%u unit files listed.\n", c);
return 0;
}
static int list_unit_files(int argc, char *argv[], void *userdata) {
@ -1772,7 +1645,9 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
(void) pager_open(arg_pager_flags);
typesafe_qsort(units, c, compare_unit_file_list);
output_unit_file_list(units, c);
r = output_unit_file_list(units, c);
if (r < 0)
return r;
if (install_client_side())
for (unit = units; unit < units + c; unit++)
@ -2081,94 +1956,77 @@ static int get_machine_list(
return c;
}
static void output_machines_list(struct machine_info *machine_infos, unsigned n) {
static int output_machines_list(struct machine_info *machine_infos, unsigned n) {
_cleanup_(table_unrefp) Table *table = NULL;
struct machine_info *m;
unsigned
circle_len = 0,
namelen = STRLEN("NAME"),
statelen = STRLEN("STATE"),
failedlen = STRLEN("FAILED"),
jobslen = STRLEN("JOBS");
bool state_missing = false;
int r;
assert(machine_infos || n == 0);
for (m = machine_infos; m < machine_infos + n; m++) {
namelen = MAX(namelen,
strlen(m->name) + (m->is_host ? STRLEN(" (host)") : 0));
statelen = MAX(statelen, strlen_ptr(m->state));
failedlen = MAX(failedlen, DECIMAL_STR_WIDTH(m->n_failed_units));
jobslen = MAX(jobslen, DECIMAL_STR_WIDTH(m->n_jobs));
table = table_new("", "name", "state", "failed", "jobs");
if (!table)
return log_oom();
if (!arg_plain && m->state && !streq(m->state, "running"))
circle_len = 2;
}
if (!arg_no_legend) {
if (circle_len > 0)
fputs(" ", stdout);
printf("%-*s %-*s %-*s %-*s\n",
namelen, "NAME",
statelen, "STATE",
failedlen, "FAILED",
jobslen, "JOBS");
}
table_set_header(table, !arg_no_legend);
if (arg_full)
table_set_width(table, 0);
for (m = machine_infos; m < machine_infos + n; m++) {
const char *on_state = "", *off_state = "";
const char *on_failed = "", *off_failed = "";
_cleanup_free_ char *mname = NULL;
const char *on_state = "", *on_failed = "";
bool circle = false;
if (streq_ptr(m->state, "degraded")) {
on_state = ansi_highlight_red();
off_state = ansi_normal();
circle = true;
} else if (!streq_ptr(m->state, "running")) {
on_state = ansi_highlight_yellow();
off_state = ansi_normal();
circle = true;
}
if (m->n_failed_units > 0) {
if (m->n_failed_units > 0)
on_failed = ansi_highlight_red();
off_failed = ansi_normal();
} else
on_failed = off_failed = "";
if (circle_len > 0)
printf("%s%s%s ", on_state, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ", off_state);
else
on_failed = "";
if (!m->state)
state_missing = true;
if (m->is_host)
printf("%-*s (host) %s%-*s%s %s%*" PRIu32 "%s %*" PRIu32 "\n",
(int) (namelen - strlen(" (host)")),
strna(m->name),
on_state, statelen, strna(m->state), off_state,
on_failed, failedlen, m->n_failed_units, off_failed,
jobslen, m->n_jobs);
else
printf("%-*s %s%-*s%s %s%*" PRIu32 "%s %*" PRIu32 "\n",
namelen, strna(m->name),
on_state, statelen, strna(m->state), off_state,
on_failed, failedlen, m->n_failed_units, off_failed,
jobslen, m->n_jobs);
mname = strjoin(strna(m->name), " (host)");
r = table_add_many(table,
TABLE_STRING, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ",
TABLE_SET_COLOR, on_state,
TABLE_STRING, m->is_host ? mname : strna(m->name),
TABLE_STRING, strna(m->state),
TABLE_SET_COLOR, on_state,
TABLE_UINT32, m->n_failed_units,
TABLE_SET_COLOR, on_failed,
TABLE_UINT32, m->n_jobs);
if (r < 0)
return table_log_add_error(r);
}
r = table_print(table, NULL);
if (r < 0)
return log_error_errno(r, "Failed to print the table: %m");
if (!arg_no_legend) {
printf("\n");
if (state_missing && geteuid() != 0)
printf("Notice: some information only available to privileged users was not shown.\n");
printf("%u machines listed.\n", n);
}
return 0;
}
static int list_machines(int argc, char *argv[], void *userdata) {
struct machine_info *machine_infos = NULL;
sd_bus *bus;
int r;
int r, rc;
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
@ -2181,10 +2039,10 @@ static int list_machines(int argc, char *argv[], void *userdata) {
(void) pager_open(arg_pager_flags);
typesafe_qsort(machine_infos, r, compare_machine_info);
output_machines_list(machine_infos, r);
rc = output_machines_list(machine_infos, r);
free_machines_list(machine_infos, r);
return 0;
return rc;
}
static int get_default(int argc, char *argv[], void *userdata) {
@ -2292,7 +2150,7 @@ finish:
return r;
}
static int output_waiting_jobs(sd_bus *bus, uint32_t id, const char *method, const char *prefix) {
static int output_waiting_jobs(sd_bus *bus, Table *table, uint32_t id, const char *method, const char *prefix) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
const char *name, *type;
@ -2317,8 +2175,22 @@ static int output_waiting_jobs(sd_bus *bus, uint32_t id, const char *method, con
if (r < 0)
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(reply, "(usssoo)", &other_id, &name, &type, NULL, NULL, NULL)) > 0)
printf("%s %u (%s/%s)\n", prefix, other_id, name, type);
while ((r = sd_bus_message_read(reply, "(usssoo)", &other_id, &name, &type, NULL, NULL, NULL)) > 0) {
_cleanup_free_ char *row = NULL;
int rc;
if (asprintf(&row, "%s %u (%s/%s)", prefix, other_id, name, type) < 0)
return log_oom();
rc = table_add_many(table,
TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_RIGHT),
TABLE_STRING, row,
TABLE_EMPTY,
TABLE_EMPTY);
if (rc < 0)
return table_log_add_error(r);
}
if (r < 0)
return bus_log_parse_error(r);
@ -2334,11 +2206,11 @@ struct job_info {
const char *name, *type, *state;
};
static void output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n, bool skipped) {
unsigned id_len, unit_len, type_len, state_len;
static int output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n, bool skipped) {
_cleanup_(table_unrefp) Table *table = NULL;
const struct job_info *j;
const char *on, *off;
bool shorten = false;
int r;
assert(n == 0 || jobs);
@ -2349,66 +2221,54 @@ static void output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned
printf("%sNo jobs %s.%s\n", on, skipped ? "listed" : "running", off);
}
return;
return 0;
}
(void) pager_open(arg_pager_flags);
id_len = STRLEN("JOB");
unit_len = STRLEN("UNIT");
type_len = STRLEN("TYPE");
state_len = STRLEN("STATE");
table = table_new("job", "unit", "type", "state");
if (!table)
return log_oom();
table_set_header(table, !arg_no_legend);
if (arg_full)
table_set_width(table, 0);
for (j = jobs; j < jobs + n; j++) {
uint32_t id = j->id;
assert(j->name && j->type && j->state);
id_len = MAX(id_len, DECIMAL_STR_WIDTH(id));
unit_len = MAX(unit_len, strlen(j->name));
type_len = MAX(type_len, strlen(j->type));
state_len = MAX(state_len, strlen(j->state));
}
if (!arg_full && id_len + 1 + unit_len + type_len + 1 + state_len > columns()) {
unit_len = MAX(33u, columns() - id_len - type_len - state_len - 3);
shorten = true;
}
if (!arg_no_legend)
printf("%*s %-*s %-*s %-*s\n",
id_len, "JOB",
unit_len, "UNIT",
type_len, "TYPE",
state_len, "STATE");
for (j = jobs; j < jobs + n; j++) {
_cleanup_free_ char *e = NULL;
if (streq(j->state, "running")) {
if (streq(j->state, "running"))
on = ansi_highlight();
off = ansi_normal();
} else
on = off = "";
else
on = "";
e = shorten ? ellipsize(j->name, unit_len, 33) : NULL;
printf("%*u %s%-*s%s %-*s %s%-*s%s\n",
id_len, j->id,
on, unit_len, e ? e : j->name, off,
type_len, j->type,
on, state_len, j->state, off);
r = table_add_many(table,
TABLE_UINT, j->id,
TABLE_STRING, j->name,
TABLE_SET_COLOR, on,
TABLE_STRING, j->type,
TABLE_STRING, j->state,
TABLE_SET_COLOR, on);
if (r < 0)
return table_log_add_error(r);
if (arg_jobs_after)
output_waiting_jobs(bus, j->id, "GetJobAfter", "\twaiting for job");
output_waiting_jobs(bus, table, j->id, "GetJobAfter", "\twaiting for job");
if (arg_jobs_before)
output_waiting_jobs(bus, j->id, "GetJobBefore", "\tblocking job");
output_waiting_jobs(bus, table, j->id, "GetJobBefore", "\tblocking job");
}
r = table_print(table, NULL);
if (r < 0)
return log_error_errno(r, "Failed to print the table: %m");
if (!arg_no_legend) {
on = ansi_highlight();
off = ansi_normal();
printf("\n%s%u jobs listed%s.\n", on, n, off);
}
return 0;
}
static bool output_show_job(struct job_info *job, char **patterns) {
@ -2469,8 +2329,7 @@ static int list_jobs(int argc, char *argv[], void *userdata) {
(void) pager_open(arg_pager_flags);
output_jobs_list(bus, jobs, c, skipped);
return 0;
return output_jobs_list(bus, jobs, c, skipped);
}
static int cancel_job(int argc, char *argv[], void *userdata) {

View File

@ -28,7 +28,7 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
}
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT, &m);
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
if (r < 0) {
log_error_errno(r, "Failed to dissect image: %m");
return EXIT_FAILURE;