###############################################################################
import logging
+import os
import subprocess
import sys
import tempfile
with open("/etc/os-release") as f:
return util.config_read(f)
- def command(self, command, error_ok=False, interactive=False):
+ def command(self, command, error_ok=False, interactive=False, chroot=False, bind=None):
"""
Runs a command in a shell environment
"""
log.debug("Running command: %s" % " ".join(command))
+ # Run this command in the installed environment if requested
+ if chroot:
+ command = ["chroot", self.root] + command
+
args = {}
if not interactive:
"stderr" : subprocess.STDOUT,
})
- # Execute the command
- p = subprocess.run(command, **args)
+ try:
+ # Bind-mount things
+ if bind:
+ self._bind(bind)
+
+ # Execute the command
+ p = subprocess.run(command, **args)
+
+ finally:
+ # If the command is successful or not, we will always need to unbind
+ # anything that has been mounted before.
+ if bind:
+ self._unbind(bind)
# Check the return code (raises CalledProcessError on non-zero)
if not error_ok:
return output
+ def _bind(self, mountpoints):
+ """
+ Bind-mounts the given mountpoints
+ """
+ for source in mountpoints:
+ if not source.startswith("/"):
+ raise ValueError("Mountpoints must be absolute paths")
+
+ target = os.path.join(self.root, source[1:])
+
+ # Make sure we mount into our root
+ assert(target.startswith(self.root))
+
+ # Perform mount
+ self.command(["mount", "--bind", source, target])
+
+ def _unbind(self, mountpoints):
+ """
+ Umounts any bind-mounted mountpoints
+ """
+ for source in reversed(mountpoints):
+ if not source.startswith("/"):
+ continue
+
+ target = os.path.join(self.root, source[1:])
+
+ # Make sure we mount into our root
+ assert(target.startswith(self.root))
+
+ # Perform umount
+ self.command(["umount", target], error_ok=True)
+
def setup_pakfire(self, **kwargs):
"""
Calls Pakfire and has it load its configuration
requires_bootldr_partition = True
def install(self):
- # Initialize Pakfire
- pakfire = self.bricklayer.setup_pakfire()
-
# Install GRUB2 on all disks that have been selected
for disk in self.bricklayer.disks.selected:
- self.install_on_disk(disk, pakfire)
+ self.install_on_disk(disk)
# Install configuration
- self.install_configuration(pakfire)
+ self.install_configuration()
@property
def grub_arch(self):
"--target=%s" % self.grub_arch,
]
- def install_on_disk(self, disk, pakfire):
+ def install_on_disk(self, disk):
log.info("Installing GRUB on %s" % disk.path)
- # Make /dev available in the jail
- # XXX this should be limited to the device nodes we need only
- bind = ["/dev"]
-
- pakfire.execute(["grub-install"] + self.grub_args + [disk.path], bind=bind)
+ self.bricklayer.command([
+ "grub-install", "--verbose", "--force", "--recheck",
+ *self.grub_args, disk.path,
+ ], chroot=True, bind=["/dev", "/proc", "/sys"])
- def install_configuration(self, pakfire):
+ def install_configuration(self):
"""
Generates a GRUB configuration file
"""
- # XXX see above
- bind = ["/dev"]
-
- pakfire.execute(["grub-mkconfig", "-o", "/boot/grub/grub.cfg"], bind=bind)
+ self.bricklayer.command([
+ "grub-mkconfig", "-o", "/boot/grub/grub.cfg",
+ ], chroot=True, bind=["/dev", "/proc", "/sys"])
class GrubEFI(Grub):