Skip to content

Commit e18c240

Browse files
authored
Merge branch 'desultory:main' into no-userspace-btrfs
2 parents 7adb2d8 + d1ab3bb commit e18c240

File tree

9 files changed

+109
-66
lines changed

9 files changed

+109
-66
lines changed

docs/configuration.md

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -234,19 +234,27 @@ Additional modules include:
234234
#### ugrd.fs.mounts
235235

236236
* `autodetect_root` (true) Set the root mount parameter based on the current root label or uuid.
237-
* `autodetect_root_dm` (true) Attempt to automatically configure virtual block devices such as LUKS/LVM/MDRAID.
238-
* `autodetect_root_luks` (true) Attempt to automatically configure LUKS mounts for the root device.
239-
* `autodetect_root_lvm` (true) Attempt to automatically configure LVM mounts for the root device.
240-
* `autodetect_root_mdraid` (true) Attempt to automatically configure MDRAID mounts for the root device.
237+
* `autodetect_dm` (true) Attempt to automatically configure virtual block devices such as LUKS/LVM/MDRAID.
238+
* `autodetect_luks` (true) Attempt to automatically configure LUKS mounts for the root device.
239+
* `autodetect_lvm` (true) Attempt to automatically configure LVM mounts for the root device.
240+
* `autodetect_mdraid` (true) Attempt to automatically configure MDRAID mounts for the root device.
241241
* `autodetect_init_mount'` (true) Automatically detect the mountpoint for the init binary, and add it to `late_mounts`.
242242
* `run_dirs` A list of directories to create under `/run/` at runtime
243243

244-
> `autodetect_root` is required for `autodetect_root_<type>` to work.
244+
> `autodetect_root` is required for `autodetect_<type>` to work.
245245
246246
`mounts`: A dictionary containing entries for mounts, with their associated config.
247247

248+
Mounts defined here are mounted before `init_main` is run. This cannot be used for mounts backed by LUKS, LVM, or MDRAID devices, because the backend will not be available when these mounts are attempted.
249+
250+
> `mounts` can be automatically populated by configuring paths as list items in `auto_mounts`.
251+
248252
`mounts.root` is predefined to have a destination of `/target_rootfs` and defines the root filesystem mount, used by `switch_root`.
249253

254+
`late_mounts`: A dictionary containing entries for mounts that should be mounted after `init_main` is run.
255+
256+
> `late_mounts` can be automatically populated by configuring paths as list items in `auto_late_mounts`.
257+
250258
Each mount has the following available parameters:
251259

252260
* `type` (auto) Mount filesystem type.
@@ -285,6 +293,8 @@ label = "extra"
285293

286294
Paths added to `auto_mounts` will be auto-configured to mount before `init_main` is run.
287295

296+
Paths added to `auto_late_mounts` will be auto-configured to mount after `init_main` is run.
297+
288298
#### ugrd.fs.fakeudev
289299

290300
This module is used to create fake udev entries for DM devices.

examples/luks.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ modules = [
77
]
88

99
# Device mapper autodetection is enabled by default
10-
# autodetect_root_luks = true
10+
# autodetect_luks = true
1111

1212
# Information about the LUKS volume can be manually specified
1313
#[cryptsetup.root]

readme.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,19 @@ The original goal of this project was to create an initramfs suitable for decryp
2626
### Auto-detection
2727

2828
* Root mount, using `/proc/mounts`. `root=` and `rootflags=` can be used but are not required
29-
* MDRAID auto-configuration for the root mount
30-
* LUKS auto-configuration and validation for the root mount
29+
* MDRAID auto-configuration
30+
* LVM auto-configuration
31+
* LUKS auto-configuration and validation
3132
- LUKS under LVM support
3233
- LUKS under MDRAID support
33-
* LVM based root volumes are auto-mounted
34-
* BTRFS root subvolumes are automatically detected to `root_subvol`
35-
- `subvol_selector` can be used to select a subvolume at boot time
36-
* `/usr` auto-mounting if the init system requires it
37-
* Auto-detection of kernel modules required by the storage device used by the root filesystem
34+
- Detached header support
35+
- YubiKey (OpenPGP smartcard) support
36+
- Recovery using a passprhase using `try_nokey`
37+
- DM-Integrity support
38+
* BTRFS root subvolumes are automatically detected or can be manually set with `root_subvol`
39+
- `subvol_selector` can be used to interactively select a subvolume at boot time
40+
* `/usr`, `/var`, and `/etc` auto-mounting if the init system requires it
41+
* Auto-detection of kernel modules required by storage devices and filesystems
3842
* Init system/target auto-detection
3943

4044
### Validation

src/ugrd/crypto/cryptsetup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def _validate_cryptsetup_config(self, mapped_name: str) -> None:
100100
).exists(): # Make sure the header file exists, it may not be present at build time
101101
self.logger.warning("[%s] Header file not found: %s" % (mapped_name, c_(config["header_file"], "yellow")))
102102
elif not any([config.get("partuuid"), config.get("uuid"), config.get("path")]):
103-
if not self["autodetect_root_luks"]:
103+
if not self["autodetect_luks"]:
104104
raise ValidationError(
105105
"A device uuid, partuuid, or path must be specified for cryptsetup mount: %s" % mapped_name
106106
)

src/ugrd/fs/mounts.py

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
__author__ = "desultory"
2-
__version__ = "7.2.1"
2+
__version__ = "7.3.0"
33

44
from pathlib import Path
55
from re import search
@@ -436,7 +436,7 @@ def get_virtual_block_info(self):
436436
sys_block = Path("/sys/devices/virtual/block")
437437

438438
if not sys_block.exists():
439-
self["autodetect_root_dm"] = False
439+
self["autodetect_dm"] = False
440440
return self.logger.warning("Virtual block devices unavailable, disabling device mapper autodetection.")
441441

442442
devices = []
@@ -450,7 +450,7 @@ def get_virtual_block_info(self):
450450
devices.append(part)
451451

452452
if not devices:
453-
self["autodetect_root_dm"] = False
453+
self["autodetect_dm"] = False
454454
return self.logger.warning("No virtual block devices found, disabling device mapper autodetection.")
455455

456456
for virt_dev in devices:
@@ -541,6 +541,17 @@ def _autodetect_dm(self, mountpoint, device=None) -> None:
541541
major, minor = _get_device_id(source_device)
542542
self.logger.debug("[%s] Major: %s, Minor: %s" % (source_device, major, minor))
543543

544+
# If the mountpoint is in auto_mounts, log a big error about it being prone to failure, allow
545+
if mountpoint in self["auto_mounts"]:
546+
self.logger.error(f"Found a device mapper mount in auto_mounts: {c_(mountpoint, 'yellow', bold=True)}")
547+
self.logger.warning(
548+
"auto_mounts is used for mounts before LVM/LUKS init (during mount_fstab). Device mapper mounts defined here may fail to activate and stop the boot process!"
549+
)
550+
if self["validate"]:
551+
raise ValidationError(
552+
f"Device mapper mount found in auto_mounts, auto_mounts cannot be device mapper based: {c_(mountpoint, 'red', bold=True)}"
553+
)
554+
544555
# Get the virtual block device name using the major/minor
545556
for name, info in self["_vblk_info"].items():
546557
if info["major"] == str(major) and info["minor"] == str(minor):
@@ -559,7 +570,9 @@ def _autodetect_dm(self, mountpoint, device=None) -> None:
559570
# If the slave source is a CRYPT-SUBDEV device, use its slave instead
560571
if self["_vblk_info"].get(slave_source, {}).get("uuid", "").startswith("CRYPT-SUBDEV"):
561572
slave_source = self["_vblk_info"][slave_source]["slaves"][0]
562-
self.logger.info(f"[{c_(dev_name, 'blue')}] Slave is a CRYPT-SUBDEV, using its slave instead: {c_(slave_source, 'cyan')}")
573+
self.logger.info(
574+
f"[{c_(dev_name, 'blue')}] Slave is a CRYPT-SUBDEV, using its slave instead: {c_(slave_source, 'cyan')}"
575+
)
563576
# Add the kmod for it
564577
self.logger.info(f"[{c_(dev_name, 'blue')}] Adding kmod for CRYPT-SUBDEV: {c_('dm-crypt', 'magenta')}")
565578
self["_kmod_auto"] = ["dm_integrity", "authenc"]
@@ -624,7 +637,7 @@ def _autodetect_dm(self, mountpoint, device=None) -> None:
624637
self.logger.debug("Slave does not appear to be a DM device: %s" % slave)
625638

626639

627-
@contains("autodetect_root_raid", "Skipping RAID autodetection, autodetect_root_raid is disabled.", log_level=30)
640+
@contains("autodetect_raid", "Skipping RAID autodetection, autodetect_raid is disabled.", log_level=30)
628641
@contains("hostonly", "Skipping RAID autodetection, hostonly mode is disabled.", log_level=30)
629642
def autodetect_raid(self, source_dev, dm_name, blkid_info) -> None:
630643
"""Autodetects MD RAID mounts and sets the raid config.
@@ -641,7 +654,7 @@ def autodetect_raid(self, source_dev, dm_name, blkid_info) -> None:
641654
raise AutodetectError("[%s] Failed to autodetect MDRAID level: %s" % (dm_name, blkid_info))
642655

643656

644-
@contains("autodetect_root_lvm", "Skipping LVM autodetection, autodetect_root_lvm is disabled.", log_level=20)
657+
@contains("autodetect_lvm", "Skipping LVM autodetection, autodetect_lvm is disabled.", log_level=20)
645658
@contains("hostonly", "Skipping LVM autodetection, hostonly mode is disabled.", log_level=30)
646659
def autodetect_lvm(self, source_dev, dm_num, blkid_info) -> None:
647660
"""Autodetects LVM mounts and sets the lvm config."""
@@ -664,7 +677,7 @@ def autodetect_lvm(self, source_dev, dm_num, blkid_info) -> None:
664677
self["lvm"] = {source_dev.name: lvm_config}
665678

666679

667-
@contains("autodetect_root_luks", "Skipping LUKS autodetection, autodetect_root_luks is disabled.", log_level=30)
680+
@contains("autodetect_luks", "Skipping LUKS autodetection, autodetect_luks is disabled.", log_level=30)
668681
@contains("hostonly", "Skipping LUKS autodetection, hostonly mode is disabled.", log_level=30)
669682
def autodetect_luks(self, source_dev, dm_num, blkid_info) -> None:
670683
"""Autodetects LUKS mounts and sets the cryptsetup config."""
@@ -747,22 +760,10 @@ def autodetect_root(self) -> None:
747760
raise AutodetectError(
748761
"Root mount not found in host mounts.\nCurrent mounts: %s" % pretty_print(self["_mounts"])
749762
)
750-
root_dev = _autodetect_mount(self, "/")
751-
if self["autodetect_root_dm"]:
752-
if self["mounts"]["root"]["type"] == "btrfs":
753-
from ugrd.fs.btrfs import _get_btrfs_mount_devices
754-
755-
# Btrfs volumes may be backed by multiple dm devices
756-
for device in _get_btrfs_mount_devices(self, "/", root_dev):
757-
_autodetect_dm(self, "/", device)
758-
elif self["mounts"]["root"]["type"] == "zfs":
759-
for device in get_zpool_info(self, root_dev)["devices"]:
760-
_autodetect_dm(self, "/", device)
761-
else:
762-
_autodetect_dm(self, "/")
763+
_autodetect_mount(self, "/")
763764

764765

765-
def _autodetect_mount(self, mountpoint, mount_class="mounts", missing_ok=False) -> str:
766+
def _autodetect_mount(self, mountpoint, mount_class="mounts", missing_ok=False) -> None:
766767
"""Sets mount config for the specified mountpoint, in the specified mount class.
767768
768769
Returns the "real" device path for the mountpoint.
@@ -815,7 +816,7 @@ def _autodetect_mount(self, mountpoint, mount_class="mounts", missing_ok=False)
815816
# Inherit mount options from the host mount for certain mount types
816817
if fs_type in MOUNT_INHERIT_OPTIONS:
817818
mount_options = self["_mounts"][mountpoint].get("options", ["ro"])
818-
if 'rw' in mount_options:
819+
if "rw" in mount_options:
819820
mount_options.pop(mount_options.index("rw")) # Remove rw option if it exists
820821
else: # For standard mounts, default ro
821822
mount_options = ["ro"]
@@ -840,8 +841,21 @@ def _autodetect_mount(self, mountpoint, mount_class="mounts", missing_ok=False)
840841
if fs_type == "zfs":
841842
mount_config[mount_name]["path"] = mount_device
842843

844+
# Run device mapper autodetection if enabled
845+
if self["autodetect_dm"]:
846+
if fs_type == "btrfs":
847+
from ugrd.fs.btrfs import _get_btrfs_mount_devices
848+
849+
# Btrfs volumes may be backed by multiple dm devices
850+
for device in _get_btrfs_mount_devices(self, mountpoint, mount_device):
851+
_autodetect_dm(self, mountpoint, mount_device)
852+
elif fs_type == "zfs":
853+
for device in get_zpool_info(self, mount_device)["devices"]:
854+
_autodetect_dm(self, mountpoint, mount_device)
855+
else:
856+
_autodetect_dm(self, mountpoint)
857+
843858
self[mount_class] = mount_config
844-
return mount_device
845859

846860

847861
@contains("auto_mounts", "Skipping auto mounts, auto_mounts is empty.", log_level=10)
@@ -852,6 +866,14 @@ def autodetect_mounts(self) -> None:
852866
_autodetect_mount(self, mountpoint)
853867

854868

869+
@contains("auto_late_mounts", "Skipping auto late mounts, auto_late_mounts is empty.", log_level=10)
870+
@contains("hostonly", "Skipping late mount autodetection, hostonly mode is disabled.", log_level=30)
871+
def autodetect_late_mounts(self) -> None:
872+
"""Configured the late_mounts config for a device based on the host mount config."""
873+
for mountpoint in self["auto_late_mounts"]:
874+
_autodetect_mount(self, mountpoint, mount_class="late_mounts")
875+
876+
855877
def mount_base(self) -> list[str]:
856878
"""Generates mount commands for the base mounts.
857879
Must be run before variables are used, as it creates the /run/ugrd directory.
@@ -906,7 +928,9 @@ def mount_fstab(self) -> list[str]:
906928
mount_retries sets the number of times to retry the mount, infinite otherwise.
907929
"""
908930
if not self._get_build_path("/etc/fstab").exists():
909-
return self.logger.info("No initramfs fstab found, skipping mount_fstab. If non-root storage devices are not needed at boot, this is fine.")
931+
return self.logger.info(
932+
"No initramfs fstab found, skipping mount_fstab. If non-root storage devices are not needed at boot, this is fine."
933+
)
910934

911935
out = [
912936
'einfo "Attempting to mount all filesystems."',
@@ -1039,8 +1063,12 @@ def export_mount_info(self) -> None:
10391063
self.logger.critical(f"Failed to get source info for the root mount: {e}")
10401064
if not self["hostonly"]:
10411065
self.logger.info("Root mount infomrmation can be defined under the '[mounts.root]' section.")
1042-
raise ValidationError("Root mount source information is not set, when hostonly mode is disabled, it must be manually defined.")
1043-
raise ValidationError("Root mount source information is not set even though hostonly mode is enabled. Please report a bug.")
1066+
raise ValidationError(
1067+
"Root mount source information is not set. When hostonly mode is disabled, it must be manually defined."
1068+
)
1069+
raise ValidationError(
1070+
"Root mount source information is not set even though hostonly mode is enabled. Please report a bug."
1071+
)
10441072
self["exports"]["MOUNTS_ROOT_TYPE"] = self["mounts"]["root"].get("type", "auto")
10451073
self["exports"]["MOUNTS_ROOT_OPTIONS"] = ",".join(self["mounts"]["root"]["options"])
10461074
self["exports"]["MOUNTS_ROOT_TARGET"] = self["mounts"]["root"]["destination"]

src/ugrd/fs/mounts.toml

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ run_dirs = [ "ugrd" ]
99

1010
mount_timeout = 1
1111
autodetect_root = true
12-
autodetect_root_dm = true
13-
autodetect_root_luks = true
14-
autodetect_root_lvm = true
15-
autodetect_root_raid = true
12+
autodetect_dm = true
13+
autodetect_luks = true
14+
autodetect_lvm = true
15+
autodetect_raid = true
1616
autodetect_init_mount = true
1717

1818
[imports.config_processing]
@@ -22,7 +22,7 @@ autodetect_init_mount = true
2222

2323
[imports.build_enum]
2424
"ugrd.fs.mounts" = [ "get_mounts_info", "get_virtual_block_info", "get_blkid_info", "get_zpool_info",
25-
"autodetect_root", "autodetect_mounts", "autodetect_init_mount" ]
25+
"autodetect_root", "autodetect_mounts", "autodetect_late_mounts", "autodetect_init_mount" ]
2626

2727
[imports.build_tasks]
2828
"ugrd.fs.mounts" = [ "export_mount_info" ]
@@ -58,14 +58,15 @@ mount_devpts = "bool" # Whether or not to mount devpts
5858
run_dirs = "NoDupFlatList" # A list of directories to be created under /run
5959
late_mounts = "dict" # Like mounts, but run after the root is mounted
6060
auto_mounts = "NoDupFlatList" # A list of mounts to be automatically added to the mounts list
61+
auto_late_mounts = "NoDupFlatList" # A list of mounts to be automatically added to the late mounts list
6162
mount_timeout = "float" # The time to wait between mount attempts
6263
mount_retries = "int" # The number of times to re-attempt mounting the fstab, infinite if not set
6364
mount_cmd = "str" # The mount command called by mount_root, can be overridden
6465
autodetect_root = "bool" # Add the autodetect_root property, if defined, the root mount will be autodetected
65-
autodetect_root_dm = "bool" # Whether or not to try to autodetect device-mapper partitions
66-
autodetect_root_luks = "bool" # Whether or not to try to autodetect LUKS partitions
67-
autodetect_root_lvm = "bool" # Whether or not to try to autodetect LVM partitions
68-
autodetect_root_raid = "bool" # Whether or not to try to autodetect MDRAID partitions
66+
autodetect_dm = "bool" # Whether or not to try to autodetect device-mapper partitions
67+
autodetect_luks = "bool" # Whether or not to try to autodetect LUKS partitions
68+
autodetect_lvm = "bool" # Whether or not to try to autodetect LVM partitions
69+
autodetect_raid = "bool" # Whether or not to try to autodetect MDRAID partitions
6970
autodetect_init_mount = "bool" # Adds a late_mount for the init target if it exists under a mount on the host
7071
no_fsck = "bool" # Whether or not to skip fsck on the root device when applicable
7172
_mounts = "dict" # The mounts information

src/ugrd/main.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -94,36 +94,36 @@ def main():
9494
"dest": "autodetect_root",
9595
},
9696
{
97-
"flags": ["--autodetect-root-luks"],
97+
"flags": ["--autodetect-luks"],
9898
"action": "store_true",
9999
"help": "autodetect LUKS volumes under the root partition",
100100
},
101101
{
102-
"flags": ["--no-autodetect-root-luks"],
102+
"flags": ["--no-autodetect-luks"],
103103
"action": "store_false",
104-
"help": "do not autodetect root LUKS volumes",
105-
"dest": "autodetect_root_luks",
104+
"help": "do not autodetect LUKS volumes",
105+
"dest": "autodetect_luks",
106106
},
107-
{"flags": ["--autodetect-root-lvm"], "action": "store_true", "help": "autodetect LVM volumes"},
107+
{"flags": ["--autodetect-lvm"], "action": "store_true", "help": "autodetect LVM volumes"},
108108
{
109-
"flags": ["--no-autodetect-root-lvm"],
109+
"flags": ["--no-autodetect-lvm"],
110110
"action": "store_false",
111111
"help": "do not autodetect LVM volumes",
112-
"dest": "autodetect_root_lvm",
112+
"dest": "autodetect_lvm",
113113
},
114-
{"flags": ["--autodetect-root-raid"], "action": "store_true", "help": "autodetect MRRAID volumes"},
114+
{"flags": ["--autodetect-raid"], "action": "store_true", "help": "autodetect MRRAID volumes"},
115115
{
116-
"flags": ["--no-autodetect-root-raid"],
116+
"flags": ["--no-autodetect-raid"],
117117
"action": "store_false",
118118
"help": "do not autodetect MRRAID volumes",
119-
"dest": "autodetect_root_raid",
119+
"dest": "autodetect_raid",
120120
},
121-
{"flags": ["--autodetect-root-dm"], "action": "store_true", "help": "autodetect DM (LUKS/LVM) root partitions"},
121+
{"flags": ["--autodetect-dm"], "action": "store_true", "help": "autodetect DM (LUKS/LVM) root partitions"},
122122
{
123-
"flags": ["--no-autodetect-root-dm"],
123+
"flags": ["--no-autodetect-dm"],
124124
"action": "store_false",
125-
"help": "do not autodetect root DM volumes",
126-
"dest": "autodetect_root_dm",
125+
"help": "do not autodetect device mapper volumes",
126+
"dest": "autodetect_dm",
127127
},
128128
{"flags": ["--print-config"], "action": "store_true", "help": "print the final config dict"},
129129
{"flags": ["--print-init"], "action": "store_true", "help": "print the final init structure"},
@@ -156,7 +156,7 @@ def main():
156156
if test:
157157
logger.warning("TEST MODE ENABLED")
158158
logger.info("Disabling DM autodetection")
159-
kwargs["autodetect_root_dm"] = False
159+
kwargs["autodetect_dm"] = False
160160
kwargs["modules"] = kwargs["modules"] + ",ugrd.base.test" if kwargs.get("modules") else "ugrd.base.test"
161161

162162
logger.debug(f"Using the following kwargs: {kwargs}")

tests/fs/overlayfs.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ modules = [ "ugrd.base.test", "ugrd.fs.overlayfs"]
33

44
out_dir = "initramfs_test"
55
cpio_compression = false
6-
autodetect_root_dm = false
6+
autodetect_dm = false

tests/fullauto.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ out_dir = "initramfs_test"
1212
#test_kernel = "/boot/vmlinuz-6.6.35-gentoo-dist"
1313
cpio_compression = false
1414

15-
autodetect_root_dm = false
15+
autodetect_dm = false
1616

1717
# Optionally supply a kernel version, uses the current kernel version if not specified
1818
#kernel_version = "6.1.53-gentoo-dist"

0 commit comments

Comments
 (0)