diff --git a/docs/configuration.md b/docs/configuration.md index 6c1ed125..a4f6fea2 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -26,6 +26,7 @@ Modules write to a shared config dict that is accessible by other modules. > The main module, mostly pulls basic binaries and pulls the `core`, `mounts`, and `cpio` module. +* `switch_root_target` Set the target filesystem for `switch_root`, defaults to the root mountpoint if not set. * `init_target` Sets the init target for `switch_root`. * `autodetect_init` (true) Automatically set the init target based `which init`. * `loglevel` (5) Sets the kernel log level in the init script. diff --git a/examples/livegui.toml b/examples/livegui.toml new file mode 100644 index 00000000..a75e407b --- /dev/null +++ b/examples/livegui.toml @@ -0,0 +1,2 @@ +modules = [ "ugrd.fs.livecd" ] +livecd_label = "gentoo-amd64-livegui" diff --git a/src/ugrd/base/base.py b/src/ugrd/base/base.py index 44ad1a3f..f4984099 100644 --- a/src/ugrd/base/base.py +++ b/src/ugrd/base/base.py @@ -1,5 +1,5 @@ __author__ = "desultory" -__version__ = "5.1.4" +__version__ = "5.2.0" from importlib.metadata import version from pathlib import Path @@ -46,12 +46,20 @@ def autodetect_init(self) -> None: raise FileNotFoundError("init_target is not specified and could not be detected.") +def export_switch_root_target(self) -> None: + """Adds SWITCH_ROOT_TARGET to exports. + Uses switch_root_target if set, otherwise uses the rootfs.""" + switch_root_target = self["switch_root_target"] + if str(switch_root_target) == ".": # Handle empty Path + switch_root_target = self["mounts"]["root"]["destination"] + self["exports"]["SWITCH_ROOT_TARGET"] = switch_root_target + def _find_init(self) -> str: """Returns bash to find the init_target.""" return [ 'for init_path in "/sbin/init" "/bin/init" "/init"; do', - ' if [ -e "$(readvar MOUNTS_ROOT_TARGET)$init_path" ] ; then', - ' einfo "Found init at: $(readvar MOUNTS_ROOT_TARGET)$init_path"', + ' if [ -e "$(readvar SWITCH_ROOT_TARGET)$init_path" ] ; then', + ' einfo "Found init at: $(readvar SWITCH_ROOT_TARGET)$init_path"', ' setvar init "$init_path"', " return", " fi", @@ -68,9 +76,8 @@ def set_loglevel(self) -> list[str]: @contains("init_target", "init_target must be set.", raise_exception=True) def do_switch_root(self) -> list[str]: - """ - Should be the final statement, switches root. - Checks if the root mount is mounted and that it contains an init. + """Should be the final statement, switches root. + Checks if the switch_root target is mounted, and that it contains an init. If not, it restarts UGRD. """ return [ @@ -79,21 +86,21 @@ def do_switch_root(self) -> list[str]: " exit 1", "fi", 'init_target=$(readvar init) || rd_fail "init_target not set."', # should be set, if unset, checks fail - 'einfo "Checking root mount: $(readvar MOUNTS_ROOT_TARGET)"', - 'if ! grep -q " $(readvar MOUNTS_ROOT_TARGET) " /proc/mounts ; then', - ' rd_fail "Root not found at: $(readvar MOUNTS_ROOT_TARGET)"', - 'elif [ ! -e "$(readvar MOUNTS_ROOT_TARGET)${init_target}" ] ; then', - ' ewarn "$init_target not found at: $(readvar MOUNTS_ROOT_TARGET)"', - r' einfo "Target root contents:\n$(ls -l "$(readvar MOUNTS_ROOT_TARGET)")"', + 'einfo "Checking root mount: $(readvar SWITCH_ROOT_TARGET)"', + 'if ! grep -q " $(readvar SWITCH_ROOT_TARGET) " /proc/mounts ; then', + ' rd_fail "Root not found at: $(readvar SWITCH_ROOT_TARGET)"', + 'elif [ ! -e "$(readvar SWITCH_ROOT_TARGET)${init_target}" ] ; then', + ' ewarn "$init_target not found at: $(readvar SWITCH_ROOT_TARGET)"', + r' einfo "Target root contents:\n$(ls -l "$(readvar SWITCH_ROOT_TARGET)")"', " if _find_init ; then", # This redefineds the var, so readvar instaed of using $init_target - ' einfo "Switching root to: $(readvar MOUNTS_ROOT_TARGET) $(readvar init)"', - ' exec switch_root "$(readvar MOUNTS_ROOT_TARGET)" "$(readvar init)"', + ' einfo "Switching root to: $(readvar SWITCH_ROOT_TARGET) $(readvar init)"', + ' exec switch_root "$(readvar SWITCH_ROOT_TARGET)" "$(readvar init)"', " fi", ' rd_fail "Unable to find init."', "else", f' einfo "Completed UGRD v{version("ugrd")}."', - ' einfo "Switching root to: $(readvar MOUNTS_ROOT_TARGET) $init_target"', - ' exec switch_root "$(readvar MOUNTS_ROOT_TARGET)" "$init_target"', + ' einfo "Switching root to: $(readvar SWITCH_ROOT_TARGET) $init_target"', + ' exec switch_root "$(readvar SWITCH_ROOT_TARGET)" "$init_target"', "fi", ] diff --git a/src/ugrd/base/base.toml b/src/ugrd/base/base.toml index 590a0121..cd18d078 100644 --- a/src/ugrd/base/base.toml +++ b/src/ugrd/base/base.toml @@ -20,6 +20,9 @@ autodetect_init = true [imports.build_enum] "ugrd.base.base" = [ "autodetect_init" ] +[imports.build_tasks] +"ugrd.base.base" = [ "export_switch_root_target" ] + [imports.init_early] "ugrd.base.base" = [ "set_loglevel" ] @@ -32,6 +35,7 @@ autodetect_init = true "rd_fail", "rd_restart", "_find_init" ] [custom_parameters] +switch_root_target = "Path" # Specifies the location of the new root filesystem init_target = "Path" # Specifies the location of the system init file autodetect_init = "bool" # If set to true, the init_target will be autodetected based on the system's init system loglevel = "int" # Set the kernel log level at /proc/sys/kernel/printk diff --git a/src/ugrd/fs/livecd.py b/src/ugrd/fs/livecd.py index c67314da..a9d01ed7 100644 --- a/src/ugrd/fs/livecd.py +++ b/src/ugrd/fs/livecd.py @@ -1,24 +1,29 @@ __author__ = "desultory" -__version__ = "0.3.0" +__version__ = "0.5.0" from zenlib.util import contains @contains("livecd_label", "livecd_label must be set to the label of the livecd.", raise_exception=True) def generate_livecd_mount(self): - """ Makes the mounts entry for livecd base. """ - self['mounts'] = {'livecd': {'label': self.livecd_label, 'no_validate': True}} + """Makes the mounts entry for livecd base.""" + self["mounts"] = {"livecd": {"label": self.livecd_label, "no_validate": True}} + + +def prepare_squashfs_mount(self) -> str: + """Create the folder for the squashfs mount in /run""" + return "edebug $(mkdir -pv /run/squashfs)" @contains("squashfs_image", "squashfs_image must be set to the path of the squashfs image to mount.", raise_exception=True) -def mount_squashfs(self): - """ - Returns bash lines to mount squashfs image. - Creates /run/squashfs directory to mount squashfs image. - Creates /run/upperdir and /run/workdir directories for overlayfs. - """ - return ["einfo $(mkdir -pv /run/squashfs)", - f"mount -t squashfs -o loop /livecd/{self.squashfs_image} /run/squashfs || rd_fail 'Failed to mount squashfs image: {self.squashfs_image}'", - "edebug $(mkdir -pv /run/upperdir)", - "edebug $(mkdir -pv /run/workdir)", - f"mount -t overlay overlay -o lowerdir=/run/squashfs,upperdir=/run/upperdir,workdir=/run/workdir {self.mounts['root']['destination']} || rd_fail 'Failed to mount overlayfs'"] +def set_squashfs_mount(self): + """Updates the root mount entry to use the squashfs image.""" + self["mounts"] = { + "root": { + "type": "squashfs", + "options": ["loop"], + "path": f"/livecd/{self.squashfs_image}", + "destination": "/run/squashfs", + "no_validate": True, + } + } diff --git a/src/ugrd/fs/livecd.toml b/src/ugrd/fs/livecd.toml index f17c5a6d..fc5948e4 100644 --- a/src/ugrd/fs/livecd.toml +++ b/src/ugrd/fs/livecd.toml @@ -1,20 +1,16 @@ -autodetect_root = false -autodetect_root_dm = false +modules = ["ugrd.fs.overlayfs"] squashfs_image = 'image.squashfs' +lowerdir = "/run/squashfs" +hostonly = false -kmod_init = ['hfsplus', 'nls_utf8', 'squashfs', 'overlay', 'isofs', 'loop'] +kmod_init = ['hfsplus', 'nls_utf8', 'squashfs', 'isofs', 'loop'] [imports.build_pre] -"ugrd.fs.livecd" = ["generate_livecd_mount"] +"ugrd.fs.livecd" = ["generate_livecd_mount", "set_squashfs_mount"] -[imports.init_mount] -"ugrd.fs.livecd" = ["mount_squashfs"] - -[masks] -init_mount = "mount_cmdline_root" # Don't use the normal mount process -build_tasks = "export_mount_info" -functions = "mount_root" +[imports.init_early] +"ugrd.fs.livecd" = ["prepare_squashfs_mount"] [custom_parameters] squashfs_image = "Path" # the path to the squashfs image (at runtime) diff --git a/src/ugrd/fs/mounts.py b/src/ugrd/fs/mounts.py index 6afd3801..0c7e01c6 100644 --- a/src/ugrd/fs/mounts.py +++ b/src/ugrd/fs/mounts.py @@ -1,5 +1,5 @@ __author__ = "desultory" -__version__ = "5.4.0" +__version__ = "5.4.2" from pathlib import Path @@ -216,7 +216,7 @@ def umount_fstab(self) -> list[str]: for mount_info in self["mounts"].values(): if mount_info.get("base_mount"): continue - if str(mount_info.get("destination")) == "/target_rootfs": + if str(mount_info.get("destination")) == str(self["mounts"]["root"]["destination"]): continue mountpoints.append(str(mount_info["destination"])) @@ -729,10 +729,6 @@ def export_mount_info(self) -> None: self["exports"]["MOUNTS_ROOT_SOURCE"] = _get_mount_str(self, self["mounts"]["root"]) self["exports"]["MOUNTS_ROOT_TYPE"] = self["mounts"]["root"].get("type", "auto") self["exports"]["MOUNTS_ROOT_OPTIONS"] = ",".join(self["mounts"]["root"]["options"]) - - -def export_root_target(self) -> None: - """Exports the root target path to /run/MOUNTS_ROOT_TARGET""" self["exports"]["MOUNTS_ROOT_TARGET"] = self["mounts"]["root"]["destination"] diff --git a/src/ugrd/fs/mounts.toml b/src/ugrd/fs/mounts.toml index 473e80e7..d4077c74 100644 --- a/src/ugrd/fs/mounts.toml +++ b/src/ugrd/fs/mounts.toml @@ -30,7 +30,7 @@ late_fstab = "/etc/fstab.late" "autodetect_root", "autodetect_mounts", "autodetect_root_dm", "autodetect_init_mount" ] [imports.build_tasks] -"ugrd.fs.mounts" = [ "export_mount_info", "export_root_target" ] +"ugrd.fs.mounts" = [ "export_mount_info" ] [imports.build_final] "ugrd.fs.mounts" = [ "check_mounts", "generate_fstab" ] diff --git a/src/ugrd/fs/overlayfs.py b/src/ugrd/fs/overlayfs.py new file mode 100644 index 00000000..43a26f80 --- /dev/null +++ b/src/ugrd/fs/overlayfs.py @@ -0,0 +1,22 @@ +from zenlib.util import unset + +@unset('lowerdir', "lowerdir is already set, skipping detection.") +def detect_lowerdir(self): + """Detect the lowerdir using the mounts['root']['destination']""" + self['lowerdir'] = self.mounts['root']['destination'] + self.logger.info("Detected lowerdir: %s" % self['lowerdir']) + + +def init_overlayfs(self) -> list[str]: + """Returns bash lines to create the upperdir and workdir + Uses /run/upperdir and /run/workdir.""" + return ["edebug $(mkdir -pv /run/upperdir /run/workdir)"] + +def mount_overlayfs(self) -> list[str]: + """Returns bash lines to mount the overlayfs based on the lowerdir""" + return [ + "einfo $(mount -t overlay overlay -o lowerdir=%s,upperdir=/run/upperdir,workdir=/run/workdir $(readvar SWITCH_ROOT_TARGET))" % self['lowerdir'] + ] + + + diff --git a/src/ugrd/fs/overlayfs.toml b/src/ugrd/fs/overlayfs.toml new file mode 100644 index 00000000..cfd43200 --- /dev/null +++ b/src/ugrd/fs/overlayfs.toml @@ -0,0 +1,13 @@ +kmod_init = ["overlay"] + +[imports.build_pre] +"ugrd.fs.overlayfs" = ["detect_lowerdir"] + +[imports.init_early] +"ugrd.fs.overlayfs" = ["init_overlayfs"] + +[imports.init_mount] +"ugrd.fs.overlayfs" = ["mount_overlayfs"] + +[custom_parameters] +lowerdir = "Path" diff --git a/src/ugrd/kmod/kmod.py b/src/ugrd/kmod/kmod.py index c02ffb40..9d92e881 100644 --- a/src/ugrd/kmod/kmod.py +++ b/src/ugrd/kmod/kmod.py @@ -1,5 +1,5 @@ __author__ = 'desultory' -__version__ = '2.16.1' +__version__ = '2.16.2' from pathlib import Path from subprocess import run @@ -124,7 +124,7 @@ def _autodetect_modules_lsmod(self) -> None: @unset('no_kmod', "no_kmod is enabled, skipping.", log_level=30) -@contains('hostonly', "hostonly is not enabled, skipping.", log_level=30) +@contains('hostonly', "Skipping kmod autodetection, hostonly is disabled.", log_level=30) def autodetect_modules(self) -> None: """ Autodetects kernel modules from lsmod and/or lspci -k. """ if not self['kmod_autodetect_lsmod'] and not self['kmod_autodetect_lspci']: