Merge branch 'calamares:calamares' into calamares
This commit is contained in:
commit
719c6f2ff1
@ -9,25 +9,31 @@
|
||||
# should specifically set *efiBootloaderId* to "debian" because that is
|
||||
# hard-coded in `grubx64.efi`.
|
||||
---
|
||||
# A variable from global storage which overrides the value of efiBootLoader
|
||||
#efiBootLoaderVar: "packagechooser_bootloader"
|
||||
|
||||
# Define which bootloader you want to use for EFI installations
|
||||
# Possible options are 'grub', 'sb-shim' and 'systemd-boot'.
|
||||
# Possible options are 'grub', 'sb-shim', 'refind` and 'systemd-boot'.
|
||||
efiBootLoader: "grub"
|
||||
|
||||
# systemd-boot configuration files settings, set kernel search path, kernel name
|
||||
# and amount of time before default selection boots
|
||||
# systemd-boot configuration files settings
|
||||
|
||||
# kernelSearchPath is the path relative to the root of the install to search for kernels
|
||||
# A kernel is identified by finding files which match regular expression, kernelPattern
|
||||
kernelSearchPath: "/usr/lib/modules"
|
||||
kernelName: "vmlinuz"
|
||||
timeout: "10"
|
||||
kernelPattern: "^vmlinuz.*"
|
||||
|
||||
# additionalInitrdFiles is a comma seperated list of file names
|
||||
additionalInitrdFiles:
|
||||
- "/boot/amd-ucode"
|
||||
- "/boot/intel-ucode"
|
||||
# loaderEntries is an array of options to add to loader.conf for systemd-boot
|
||||
# please note that the "default" option is added programmatically
|
||||
loaderEntries:
|
||||
- "timeout 5"
|
||||
- "console-mode keep"
|
||||
|
||||
# Optionally set the menu entry name to use in systemd-boot.
|
||||
# If not specified here, these settings will be taken from branding.desc.
|
||||
#
|
||||
# bootloaderEntryName: "Generic GNU/Linux"
|
||||
# systemd-boot and refind support custom kernel params
|
||||
kernelParams: [ "quiet" ]
|
||||
|
||||
# A list of kernel names that refind should accept as kernels
|
||||
#refindKernelList: [ "linux","linux-lts","linux-zen","linux-hardened" ]
|
||||
|
||||
# GRUB 2 binary names and boot directory
|
||||
# Some distributions (e.g. Fedora) use grub2-* (resp. /boot/grub2/) names.
|
||||
|
@ -6,17 +6,13 @@ $id: https://calamares.io/schemas/bootloader
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
efiBootLoaderVar: { type: string }
|
||||
efiBootLoader: { type: string }
|
||||
kernelSearchPath: { type: string }
|
||||
kernelName: { type: string }
|
||||
timeout: { type: string } # Inserted verbatim
|
||||
additionalInitrdFiles:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
bootloaderEntryName: { type: string }
|
||||
kernelLine: { type: string }
|
||||
fallbackKernelLine: { type: string }
|
||||
kernelParams: { type: array, items: { type: string } }
|
||||
loaderEntries: { type: array, items: { type: string } }
|
||||
refindKernelList: { type: array, items: { type: string } }
|
||||
|
||||
# Programs
|
||||
grubInstall: { type: string }
|
||||
@ -27,12 +23,3 @@ properties:
|
||||
|
||||
efiBootloaderId: { type: string }
|
||||
installEFIFallback: { type: boolean }
|
||||
|
||||
required:
|
||||
- efiBootLoader
|
||||
- kernelSearchPath
|
||||
- kernelName
|
||||
- grubInstall
|
||||
- grubMkconfig
|
||||
- grubCfg
|
||||
- grubProbe
|
||||
|
@ -20,7 +20,9 @@
|
||||
# Calamares is Free Software: see the License-Identifier above.
|
||||
#
|
||||
|
||||
import fileinput
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
@ -28,8 +30,8 @@ import libcalamares
|
||||
|
||||
from libcalamares.utils import check_target_env_call
|
||||
|
||||
|
||||
import gettext
|
||||
|
||||
_ = gettext.translation("calamares-python",
|
||||
localedir=libcalamares.utils.gettext_path(),
|
||||
languages=libcalamares.utils.gettext_languages(),
|
||||
@ -39,6 +41,7 @@ _ = gettext.translation("calamares-python",
|
||||
# to make identifiers (or to clean up names to make filenames).
|
||||
file_name_sanitizer = str.maketrans(" /()", "_-__")
|
||||
|
||||
|
||||
def pretty_name():
|
||||
return _("Install bootloader.")
|
||||
|
||||
@ -59,20 +62,6 @@ def get_uuid():
|
||||
return ""
|
||||
|
||||
|
||||
def get_bootloader_entry_name():
|
||||
"""
|
||||
Passes 'bootloader_entry_name' to other routine based
|
||||
on configuration file.
|
||||
|
||||
:return:
|
||||
"""
|
||||
if "bootloaderEntryName" in libcalamares.job.configuration:
|
||||
return libcalamares.job.configuration["bootloaderEntryName"]
|
||||
else:
|
||||
branding = libcalamares.globalstorage.value("branding")
|
||||
return branding["bootloaderEntryName"]
|
||||
|
||||
|
||||
def get_kernel_line(kernel_type):
|
||||
"""
|
||||
Passes 'kernel_line' to other routine based on configuration file.
|
||||
@ -136,49 +125,43 @@ def is_zfs_root(partition):
|
||||
return partition["mountPoint"] == "/" and partition["fs"] == "zfs"
|
||||
|
||||
|
||||
def create_systemd_boot_conf(installation_root_path, efi_dir, uuid, entry, kernel, kernel_type, kernel_version):
|
||||
"""
|
||||
Creates systemd-boot configuration files based on given parameters.
|
||||
|
||||
:param installation_root_path: A string containing the absolute path to the root of the installation
|
||||
:param efi_dir: A string containing the path to the efi dir relative to the root of the installation
|
||||
:param uuid: A string containing the UUID of the root volume
|
||||
:param entry: A string containing the name of the entry as it will be displayed on boot
|
||||
:param kernel: A string containing the path to the kernel relative to the root of the installation
|
||||
:param kernel_type: A string which should be set if there is a special version of the entry, for example "fallback"
|
||||
:param kernel_version: The kernel version string
|
||||
"""
|
||||
kernel_params = ["quiet"]
|
||||
def get_kernel_params(uuid):
|
||||
kernel_params = libcalamares.job.configuration.get("kernelParams", ["quiet"])
|
||||
kernel_params.append("rw")
|
||||
|
||||
partitions = libcalamares.globalstorage.value("partitions")
|
||||
swap_uuid = ""
|
||||
swap_outer_mappername = None
|
||||
swap_outer_uuid = None
|
||||
|
||||
cryptdevice_params = []
|
||||
|
||||
have_dracut = libcalamares.utils.target_env_call(["sh", "-c", "which dracut"]) == 0
|
||||
|
||||
# Take over swap settings:
|
||||
# - unencrypted swap partition sets swap_uuid
|
||||
# - encrypted root sets cryptdevice_params
|
||||
for partition in partitions:
|
||||
if partition["fs"] == "linuxswap" and not partition.get("claimed", None):
|
||||
# Skip foreign swap
|
||||
continue
|
||||
has_luks = "luksMapperName" in partition
|
||||
if partition["fs"] == "linuxswap" and not has_luks:
|
||||
swap_uuid = partition["uuid"]
|
||||
|
||||
if (partition["fs"] == "linuxswap" and has_luks):
|
||||
if partition["fs"] == "linuxswap" and has_luks:
|
||||
swap_outer_mappername = partition["luksMapperName"]
|
||||
swap_outer_uuid = partition["luksUuid"]
|
||||
|
||||
if partition["mountPoint"] == "/" and has_luks:
|
||||
cryptdevice_params = ["cryptdevice=UUID="
|
||||
+ partition["luksUuid"]
|
||||
+ ":"
|
||||
+ partition["luksMapperName"],
|
||||
"root=/dev/mapper/"
|
||||
+ partition["luksMapperName"]]
|
||||
if have_dracut:
|
||||
cryptdevice_params = [f"rd.luks.uuid={partition['luksUuid']}"]
|
||||
else:
|
||||
cryptdevice_params = [f"cryptdevice=UUID={partition['luksUuid']}:{partition['luksMapperName']}"]
|
||||
cryptdevice_params.append(f"root=/dev/mapper/{partition['luksMapperName']}")
|
||||
|
||||
# btrfs and zfs handling
|
||||
for partition in partitions:
|
||||
# systemd-boot with a BTRFS root filesystem needs to be told abouut the root subvolume.
|
||||
# If a btrfs root subvolume wasn't set, it means the root is directly on the partition
|
||||
# and this option isn't needed
|
||||
if is_btrfs_root(partition):
|
||||
@ -190,7 +173,7 @@ def create_systemd_boot_conf(installation_root_path, efi_dir, uuid, entry, kerne
|
||||
if is_zfs_root(partition):
|
||||
zfs_root_path = get_zfs_root()
|
||||
if zfs_root_path is not None:
|
||||
kernel_params.append("zfs=" + zfs_root_path)
|
||||
kernel_params.append("root=ZFS=" + zfs_root_path)
|
||||
else:
|
||||
# Something is really broken if we get to this point
|
||||
libcalamares.utils.warning("Internal error handling zfs dataset")
|
||||
@ -204,93 +187,86 @@ def create_systemd_boot_conf(installation_root_path, efi_dir, uuid, entry, kerne
|
||||
if swap_uuid:
|
||||
kernel_params.append("resume=UUID={!s}".format(swap_uuid))
|
||||
|
||||
if have_dracut and swap_outer_uuid:
|
||||
kernel_params.append(f"rd.luks.uuid={swap_outer_uuid}")
|
||||
|
||||
if swap_outer_mappername:
|
||||
kernel_params.append("resume=/dev/mapper/{!s}".format(
|
||||
swap_outer_mappername))
|
||||
kernel_params.append(f"resume=/dev/mapper/{swap_outer_mappername}")
|
||||
|
||||
libcalamares.utils.debug("Configure: \"{!s}\"".format(f"{entry} {kernel_version}"))
|
||||
return kernel_params
|
||||
|
||||
if kernel_type == "fallback":
|
||||
version_string = kernel_version + "-fallback"
|
||||
initrd = "initrd-fallback"
|
||||
else:
|
||||
version_string = kernel_version
|
||||
initrd = "initrd"
|
||||
|
||||
def create_systemd_boot_conf(installation_root_path, efi_dir, uuid, kernel, kernel_version):
|
||||
"""
|
||||
Creates systemd-boot configuration files based on given parameters.
|
||||
|
||||
:param installation_root_path: A string containing the absolute path to the root of the installation
|
||||
:param efi_dir: A string containing the path to the efi dir relative to the root of the installation
|
||||
:param uuid: A string containing the UUID of the root volume
|
||||
:param kernel: A string containing the path to the kernel relative to the root of the installation
|
||||
:param kernel_version: The kernel version string
|
||||
"""
|
||||
|
||||
# Get the kernel params and write them to /etc/kernel/cmdline
|
||||
# This file is used by kernel-install
|
||||
kernel_params = " ".join(get_kernel_params(uuid))
|
||||
kernel_cmdline_path = os.path.join(installation_root_path, "etc", "kernel")
|
||||
os.makedirs(kernel_cmdline_path, exist_ok=True)
|
||||
with open(os.path.join(kernel_cmdline_path, "cmdline"), "w") as cmdline_file:
|
||||
cmdline_file.write(kernel_params)
|
||||
|
||||
libcalamares.utils.debug(f"Configuring kernel version {kernel_version}")
|
||||
|
||||
# get the machine-id
|
||||
with open(os.path.join(installation_root_path, "etc", "machine-id"), 'r') as machineid_file:
|
||||
machine_id = machineid_file.read().rstrip('\n')
|
||||
|
||||
# Copy kernel to a subdirectory of /efi partition
|
||||
# Ensure the directory exists
|
||||
machine_dir = os.path.join(installation_root_path + efi_dir, machine_id)
|
||||
os.makedirs(machine_dir, exist_ok=True)
|
||||
|
||||
target_efi_files_dir = os.path.join(machine_dir, kernel_version)
|
||||
os.makedirs(target_efi_files_dir, exist_ok=True)
|
||||
|
||||
kernel_path = os.path.join(installation_root_path, kernel)
|
||||
kernel_name = os.path.basename(kernel_path)
|
||||
shutil.copyfile(kernel_path, os.path.join(target_efi_files_dir, "linux"))
|
||||
|
||||
# write the entry
|
||||
lines = [
|
||||
'## Generated by Calamares\n',
|
||||
'\n',
|
||||
"title {!s}\n".format(entry),
|
||||
"version {!s}\n".format(version_string),
|
||||
"machine-id {!s}\n".format(machine_id),
|
||||
"linux {!s}\n".format(os.path.join("/", machine_id, kernel_version, "linux")),
|
||||
]
|
||||
|
||||
try:
|
||||
additional_initrd_files = libcalamares.job.configuration["additionalInitrdFiles"]
|
||||
for initrd_file in additional_initrd_files:
|
||||
libcalamares.utils.debug("Attempting to handle initrd image " + initrd_file)
|
||||
if os.path.isfile(os.path.join(installation_root_path, initrd_file.lstrip('/'))):
|
||||
libcalamares.utils.debug("Found image " + initrd_file)
|
||||
shutil.copyfile(os.path.join(installation_root_path, initrd_file.lstrip('/')), os.path.join(target_efi_files_dir, os.path.basename(initrd_file)))
|
||||
lines.append("initrd {!s}\n".format(os.path.join("/", machine_id, kernel_version, os.path.basename(initrd_file))))
|
||||
except KeyError: # If the configuration option isn't set, we can just move on
|
||||
libcalamares.utils.debug("Failed to find key additionalInitrdFiles")
|
||||
pass
|
||||
|
||||
lines.append("initrd {!s}\n".format(os.path.join("/", machine_id, kernel_version, initrd)))
|
||||
lines.append("options {!s} rw\n".format(" ".join(kernel_params)))
|
||||
|
||||
conf_path = os.path.join(installation_root_path + efi_dir,
|
||||
"loader",
|
||||
"entries",
|
||||
machine_id + "-" + version_string + ".conf")
|
||||
|
||||
with open(conf_path, 'w') as conf_file:
|
||||
for line in lines:
|
||||
conf_file.write(line)
|
||||
# Call kernel-install for each kernel
|
||||
libcalamares.utils.target_env_process_output(["kernel-install",
|
||||
"add",
|
||||
kernel_version,
|
||||
os.path.join("/", kernel)])
|
||||
|
||||
|
||||
def create_loader(loader_path, entry):
|
||||
def create_loader(loader_path, installation_root_path):
|
||||
"""
|
||||
Writes configuration for loader.
|
||||
|
||||
:param loader_path:
|
||||
:param entry:
|
||||
:param loader_path: The absolute path to the loader.conf file
|
||||
:param installation_root_path: The path to the root of the target installation
|
||||
"""
|
||||
timeout = libcalamares.job.configuration["timeout"]
|
||||
lines = [
|
||||
"timeout {!s}\n".format(timeout),
|
||||
"default {!s}\n".format(entry),
|
||||
]
|
||||
|
||||
# get the machine-id
|
||||
with open(os.path.join(installation_root_path, "etc", "machine-id"), 'r') as machineid_file:
|
||||
machine_id = machineid_file.read().rstrip('\n')
|
||||
|
||||
try:
|
||||
loader_entries = libcalamares.job.configuration["loaderEntries"]
|
||||
except KeyError:
|
||||
libcalamares.utils.debug("No aditional loader entries found in config")
|
||||
loader_entries = []
|
||||
pass
|
||||
|
||||
lines = [f"default {machine_id}*"]
|
||||
|
||||
lines.extend(loader_entries)
|
||||
|
||||
with open(loader_path, 'w') as loader_file:
|
||||
for line in lines:
|
||||
loader_file.write(line)
|
||||
loader_file.write(line + "\n")
|
||||
|
||||
|
||||
class suffix_iterator(object):
|
||||
class SuffixIterator(object):
|
||||
"""
|
||||
Wrapper for one of the "generator" classes below to behave like
|
||||
a proper Python iterator. The iterator is initialized with a
|
||||
maximum number of attempts to generate a new suffix.
|
||||
"""
|
||||
|
||||
def __init__(self, attempts, generator):
|
||||
self.generator = generator
|
||||
self.attempts = attempts
|
||||
@ -310,6 +286,7 @@ class serialEfi(object):
|
||||
"""
|
||||
EFI Id generator that appends a serial number to the given name.
|
||||
"""
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
# So the first call to next() will bump it to 0
|
||||
@ -354,6 +331,7 @@ class randomEfi(object):
|
||||
"""
|
||||
EFI Id generator that appends a random 4-digit hex number to the given name.
|
||||
"""
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
# So the first call to next() will bump it to 0
|
||||
@ -427,7 +405,7 @@ def change_efi_suffix(efi_directory, bootloader_id):
|
||||
"""
|
||||
if bootloader_id.endswith("}") and "${" in bootloader_id:
|
||||
# Do 10 attempts with any suffix generator
|
||||
g = suffix_iterator(10, get_efi_suffix_generator(bootloader_id))
|
||||
g = SuffixIterator(10, get_efi_suffix_generator(bootloader_id))
|
||||
else:
|
||||
# Just one attempt
|
||||
g = [bootloader_id]
|
||||
@ -444,7 +422,7 @@ def efi_label(efi_directory):
|
||||
used within @p efi_directory.
|
||||
"""
|
||||
if "efiBootloaderId" in libcalamares.job.configuration:
|
||||
efi_bootloader_id = change_efi_suffix( efi_directory, libcalamares.job.configuration["efiBootloaderId"] )
|
||||
efi_bootloader_id = change_efi_suffix(efi_directory, libcalamares.job.configuration["efiBootloaderId"])
|
||||
else:
|
||||
branding = libcalamares.globalstorage.value("branding")
|
||||
efi_bootloader_id = branding["bootloaderEntryName"]
|
||||
@ -482,6 +460,7 @@ def efi_boot_next():
|
||||
if boot_entry:
|
||||
subprocess.call([boot_mgr, "-n", boot_entry])
|
||||
|
||||
|
||||
def get_kernels(installation_root_path):
|
||||
"""
|
||||
Gets a list of kernels and associated values for each kernel. This will work as is for many distros.
|
||||
@ -493,20 +472,32 @@ def get_kernels(installation_root_path):
|
||||
|
||||
Each 3-tuple contains the kernel, kernel_type and kernel_version
|
||||
"""
|
||||
kernel_search_path = libcalamares.job.configuration["kernelSearchPath"]
|
||||
source_kernel_name = libcalamares.job.configuration["kernelName"]
|
||||
try:
|
||||
kernel_search_path = libcalamares.job.configuration["kernelSearchPath"]
|
||||
except KeyError:
|
||||
libcalamares.utils.warning("No kernel pattern found in configuration, using '/usr/lib/modules'")
|
||||
kernel_search_path = "/usr/lib/modules"
|
||||
pass
|
||||
|
||||
kernel_list = []
|
||||
|
||||
# find all the installed kernels and generate default and fallback entries for each
|
||||
try:
|
||||
kernel_pattern = libcalamares.job.configuration["kernelPattern"]
|
||||
except KeyError:
|
||||
libcalamares.utils.warning("No kernel pattern found in configuration, using 'vmlinuz'")
|
||||
kernel_pattern = "vmlinuz"
|
||||
pass
|
||||
|
||||
# find all the installed kernels
|
||||
for root, dirs, files in os.walk(os.path.join(installation_root_path, kernel_search_path.lstrip('/'))):
|
||||
for file in files:
|
||||
if file == source_kernel_name:
|
||||
if re.search(kernel_pattern, file):
|
||||
rel_root = os.path.relpath(root, installation_root_path)
|
||||
kernel_list.append((os.path.join(rel_root, file),"default",os.path.basename(root)))
|
||||
kernel_list.append((os.path.join(rel_root, file),"fallback",os.path.basename(root)))
|
||||
kernel_list.append((os.path.join(rel_root, file), "default", os.path.basename(root)))
|
||||
|
||||
return kernel_list
|
||||
|
||||
|
||||
def install_systemd_boot(efi_directory):
|
||||
"""
|
||||
Installs systemd-boot as bootloader for EFI setups.
|
||||
@ -517,8 +508,6 @@ def install_systemd_boot(efi_directory):
|
||||
installation_root_path = libcalamares.globalstorage.value("rootMountPoint")
|
||||
install_efi_directory = installation_root_path + efi_directory
|
||||
uuid = get_uuid()
|
||||
distribution = get_bootloader_entry_name()
|
||||
distribution_translated = distribution.translate(file_name_sanitizer)
|
||||
loader_path = os.path.join(install_efi_directory,
|
||||
"loader",
|
||||
"loader.conf")
|
||||
@ -528,14 +517,13 @@ def install_systemd_boot(efi_directory):
|
||||
|
||||
for (kernel, kernel_type, kernel_version) in get_kernels(installation_root_path):
|
||||
create_systemd_boot_conf(installation_root_path,
|
||||
efi_directory,
|
||||
uuid,
|
||||
distribution,
|
||||
kernel,
|
||||
kernel_type,
|
||||
kernel_version)
|
||||
efi_directory,
|
||||
uuid,
|
||||
kernel,
|
||||
kernel_version)
|
||||
|
||||
create_loader(loader_path, installation_root_path)
|
||||
|
||||
create_loader(loader_path, distribution_translated)
|
||||
|
||||
def get_grub_efi_parameters():
|
||||
"""
|
||||
@ -554,15 +542,16 @@ def get_grub_efi_parameters():
|
||||
|
||||
if efi_bitness == "32":
|
||||
# Assume all 32-bitters are legacy x86
|
||||
return ("i386-efi", "grubia32.efi", "bootia32.efi")
|
||||
return "i386-efi", "grubia32.efi", "bootia32.efi"
|
||||
elif efi_bitness == "64" and cpu_type == "aarch64":
|
||||
return ("arm64-efi", "grubaa64.efi", "bootaa64.efi")
|
||||
return "arm64-efi", "grubaa64.efi", "bootaa64.efi"
|
||||
elif efi_bitness == "64" and cpu_type == "loongarch64":
|
||||
return ("loongarch64-efi", "grubloongarch64.efi", "bootloongarch64.efi")
|
||||
return "loongarch64-efi", "grubloongarch64.efi", "bootloongarch64.efi"
|
||||
elif efi_bitness == "64":
|
||||
# If it's not ARM, must by AMD64
|
||||
return ("x86_64-efi", "grubx64.efi", "bootx64.efi")
|
||||
libcalamares.utils.warning("Could not find GRUB parameters for bits {b} and cpu {c}".format(b=repr(efi_bitness), c=repr(cpu_type)))
|
||||
return "x86_64-efi", "grubx64.efi", "bootx64.efi"
|
||||
libcalamares.utils.warning(
|
||||
"Could not find GRUB parameters for bits {b} and cpu {c}".format(b=repr(efi_bitness), c=repr(cpu_type)))
|
||||
return None
|
||||
|
||||
|
||||
@ -667,8 +656,8 @@ def install_grub(efi_directory, fw_type):
|
||||
|
||||
# VFAT is weird, see issue CAL-385
|
||||
install_efi_directory_firmware = (vfat_correct_case(
|
||||
install_efi_directory,
|
||||
"EFI"))
|
||||
install_efi_directory,
|
||||
"EFI"))
|
||||
if not os.path.exists(install_efi_directory_firmware):
|
||||
os.makedirs(install_efi_directory_firmware)
|
||||
|
||||
@ -676,8 +665,8 @@ def install_grub(efi_directory, fw_type):
|
||||
# most usual they are boot, Boot, BOOT
|
||||
|
||||
install_efi_boot_directory = (vfat_correct_case(
|
||||
install_efi_directory_firmware,
|
||||
"boot"))
|
||||
install_efi_directory_firmware,
|
||||
"boot"))
|
||||
if not os.path.exists(install_efi_boot_directory):
|
||||
os.makedirs(install_efi_boot_directory)
|
||||
|
||||
@ -712,6 +701,9 @@ def install_secureboot(efi_directory):
|
||||
install_efi_bin = "shimx64.efi"
|
||||
elif efi_word_size() == "32":
|
||||
install_efi_bin = "shimia32.efi"
|
||||
else:
|
||||
libcalamares.utils.warning(f"Unknown efi word size of {efi_word_size()} found")
|
||||
return None
|
||||
|
||||
# Copied, roughly, from openSUSE's install script,
|
||||
# and pythonified. *disk* is something like /dev/sda,
|
||||
@ -725,7 +717,7 @@ def install_secureboot(efi_directory):
|
||||
libcalamares.job.configuration["grubProbe"],
|
||||
"-t", "disk", "--device-map=", install_efi_directory]).decode("ascii")
|
||||
|
||||
efi_drive_partition = efi_drive.replace("(","").replace(")","").split(",")[1]
|
||||
efi_drive_partition = efi_drive.replace("(", "").replace(")", "").split(",")[1]
|
||||
# Get the first run of digits from the partition
|
||||
efi_partition_number = None
|
||||
c = 0
|
||||
@ -765,6 +757,62 @@ def vfat_correct_case(parent, name):
|
||||
return os.path.join(parent, name)
|
||||
|
||||
|
||||
def efi_partitions(efi_boot_path):
|
||||
"""
|
||||
The (one) partition mounted on @p efi_boot_path, or an empty list.
|
||||
"""
|
||||
return [p for p in libcalamares.globalstorage.value("partitions") if p["mountPoint"] == efi_boot_path]
|
||||
|
||||
|
||||
def update_refind_config(efi_directory, installation_root_path):
|
||||
"""
|
||||
:param efi_directory: The path to the efi directory relative to the root
|
||||
:param installation_root_path: The path to the root of the installation
|
||||
"""
|
||||
try:
|
||||
kernel_list = libcalamares.job.configuration["refindKernelList"]
|
||||
except KeyError:
|
||||
libcalamares.utils.warning('refindKernelList not set. Skipping updating refind.conf')
|
||||
return
|
||||
|
||||
# Update the config in the file
|
||||
for line in fileinput.input(installation_root_path + efi_directory + "/EFI/refind/refind.conf", inplace=True):
|
||||
line = line.strip()
|
||||
if line.startswith("#extra_kernel_version_strings") or line.startswith("extra_kernel_version_strings"):
|
||||
line = line.lstrip("#")
|
||||
for kernel in kernel_list:
|
||||
if kernel not in line:
|
||||
line += "," + kernel
|
||||
print(line)
|
||||
|
||||
|
||||
def install_refind(efi_directory):
|
||||
try:
|
||||
installation_root_path = libcalamares.globalstorage.value("rootMountPoint")
|
||||
except KeyError:
|
||||
libcalamares.utils.warning('Global storage value "rootMountPoint" missing')
|
||||
|
||||
install_efi_directory = installation_root_path + efi_directory
|
||||
uuid = get_uuid()
|
||||
kernel_params = " ".join(get_kernel_params(uuid))
|
||||
conf_path = os.path.join(installation_root_path, "boot/refind_linux.conf")
|
||||
|
||||
check_target_env_call(["refind-install"])
|
||||
|
||||
with open(conf_path, "r") as refind_file:
|
||||
filedata = [x.strip() for x in refind_file.readlines()]
|
||||
|
||||
with open(conf_path, 'w') as refind_file:
|
||||
for line in filedata:
|
||||
if line.startswith('"Boot with standard options"'):
|
||||
line = f'"Boot with standard options" "{kernel_params}"'
|
||||
elif line.startswith('"Boot to single-user mode"'):
|
||||
line = f'"Boot to single-user mode" "{kernel_params}" single'
|
||||
refind_file.write(line + "\n")
|
||||
|
||||
update_refind_config(efi_directory, installation_root_path)
|
||||
|
||||
|
||||
def prepare_bootloader(fw_type):
|
||||
"""
|
||||
Prepares bootloader.
|
||||
@ -774,19 +822,47 @@ def prepare_bootloader(fw_type):
|
||||
:param fw_type:
|
||||
:return:
|
||||
"""
|
||||
efi_boot_loader = libcalamares.job.configuration["efiBootLoader"]
|
||||
|
||||
# Get the boot loader selection from global storage if it is set in the config file
|
||||
try:
|
||||
gs_name = libcalamares.job.configuration["efiBootLoaderVar"]
|
||||
if libcalamares.globalstorage.contains(gs_name):
|
||||
efi_boot_loader = libcalamares.globalstorage.value(gs_name)
|
||||
else:
|
||||
libcalamares.utils.warning(
|
||||
f"Specified global storage value not found in global storage")
|
||||
return None
|
||||
except KeyError:
|
||||
# If the conf value for using global storage is not set, use the setting from the config file.
|
||||
try:
|
||||
efi_boot_loader = libcalamares.job.configuration["efiBootLoader"]
|
||||
except KeyError:
|
||||
if fw_type == "efi":
|
||||
libcalamares.utils.warning("Configuration missing both efiBootLoader and efiBootLoaderVar on an EFI "
|
||||
"system, bootloader not installed")
|
||||
return
|
||||
else:
|
||||
pass
|
||||
|
||||
# If the user has selected not to install bootloader, bail out here
|
||||
if efi_boot_loader.casefold() == "none":
|
||||
libcalamares.utils.debug("Skipping bootloader installation since no bootloader was selected")
|
||||
return None
|
||||
|
||||
efi_directory = libcalamares.globalstorage.value("efiSystemPartition")
|
||||
|
||||
if efi_boot_loader == "systemd-boot" and fw_type == "efi":
|
||||
install_systemd_boot(efi_directory)
|
||||
elif efi_boot_loader == "sb-shim" and fw_type == "efi":
|
||||
install_secureboot(efi_directory)
|
||||
elif efi_boot_loader == "refind" and fw_type == "efi":
|
||||
install_refind(efi_directory)
|
||||
elif efi_boot_loader == "grub" or fw_type != "efi":
|
||||
install_grub(efi_directory, fw_type)
|
||||
else:
|
||||
libcalamares.utils.debug( "WARNING: the combination of "
|
||||
"boot-loader '{!s}' and firmware '{!s}' "
|
||||
"is not supported.".format(efi_boot_loader, fw_type) )
|
||||
libcalamares.utils.debug("WARNING: the combination of "
|
||||
"boot-loader '{!s}' and firmware '{!s}' "
|
||||
"is not supported.".format(efi_boot_loader, fw_type))
|
||||
|
||||
|
||||
def run():
|
||||
@ -798,16 +874,16 @@ def run():
|
||||
|
||||
fw_type = libcalamares.globalstorage.value("firmwareType")
|
||||
|
||||
if (libcalamares.globalstorage.value("bootLoader") is None and fw_type != "efi"):
|
||||
libcalamares.utils.warning( "Non-EFI system, and no bootloader is set." )
|
||||
if libcalamares.globalstorage.value("bootLoader") is None and fw_type != "efi":
|
||||
libcalamares.utils.warning("Non-EFI system, and no bootloader is set.")
|
||||
return None
|
||||
|
||||
partitions = libcalamares.globalstorage.value("partitions")
|
||||
if fw_type == "efi":
|
||||
efi_system_partition = libcalamares.globalstorage.value("efiSystemPartition")
|
||||
esp_found = [ p for p in partitions if p["mountPoint"] == efi_system_partition ]
|
||||
esp_found = [p for p in partitions if p["mountPoint"] == efi_system_partition]
|
||||
if not esp_found:
|
||||
libcalamares.utils.warning( "EFI system, but nothing mounted on {!s}".format(efi_system_partition) )
|
||||
libcalamares.utils.warning("EFI system, but nothing mounted on {!s}".format(efi_system_partition))
|
||||
return None
|
||||
|
||||
try:
|
||||
@ -817,7 +893,8 @@ def run():
|
||||
libcalamares.utils.debug("stdout:" + str(e.stdout))
|
||||
libcalamares.utils.debug("stderr:" + str(e.stderr))
|
||||
return (_("Bootloader installation error"),
|
||||
_("The bootloader could not be installed. The installation command <pre>{!s}</pre> returned error code {!s}.")
|
||||
_("The bootloader could not be installed. The installation command <pre>{!s}</pre> returned error "
|
||||
"code {!s}.")
|
||||
.format(e.cmd, e.returncode))
|
||||
|
||||
return None
|
||||
|
@ -64,6 +64,12 @@ sysconfigSetup: false
|
||||
#
|
||||
# greetd has configurable user and group; the user and group is created if it
|
||||
# does not exist, and the user is set as default-session user.
|
||||
#
|
||||
# lightdm has a list of greeters to look for, preferring them in order if
|
||||
# they are installed (if not, picks the alphabetically first greeter that is installed).
|
||||
#
|
||||
greetd:
|
||||
greeter_user: "tom_bombadil"
|
||||
greeter_group: "wheel"
|
||||
lightdm:
|
||||
preferred_greeters: ["lightdm-greeter.desktop", "slick-greeter.desktop"]
|
||||
|
@ -26,4 +26,7 @@ properties:
|
||||
greeter_user: { type: string }
|
||||
greeter_group: { type: string }
|
||||
additionalProperties: false
|
||||
|
||||
lightdm:
|
||||
type: object
|
||||
properties:
|
||||
preferred_greeters: { type: array, items: { type: string } }
|
||||
|
@ -544,6 +544,11 @@ class DMlightdm(DisplayManager):
|
||||
name = "lightdm"
|
||||
executable = "lightdm"
|
||||
|
||||
# Can be overridden in the .conf file. With no value it won't match any
|
||||
# desktop file in the xgreeters directory and instead we end up picking
|
||||
# the alphabetically first file there.
|
||||
preferred_greeters = []
|
||||
|
||||
def set_autologin(self, username, do_autologin, default_desktop_environment):
|
||||
# Systems with LightDM as Desktop Manager
|
||||
# Ideally, we should use configparser for the ini conf file,
|
||||
@ -633,41 +638,56 @@ class DMlightdm(DisplayManager):
|
||||
)
|
||||
)
|
||||
|
||||
def find_preferred_greeter(self, greeters_dir):
|
||||
"""
|
||||
On Debian, lightdm-greeter.desktop is typically a symlink managed
|
||||
by update-alternatives pointing to /etc/alternatives/lightdm-greeter
|
||||
which is also a symlink to a real .desktop file back in /usr/share/xgreeters/
|
||||
|
||||
Returns a path *into the mounted target* of the preferred greeter -- usually
|
||||
a .desktop file that specifies where the actual executable is. May return
|
||||
None to indicate nothing-was-found.
|
||||
"""
|
||||
greeters_dir = "usr/share/xgreeters"
|
||||
greeters_target_path = os.path.join(self.root_mount_point, greeters_dir)
|
||||
available_names = os.listdir(greeters_target_path)
|
||||
available_names.sort()
|
||||
desktop_names = [n for n in self.preferred_greeters if n in available_names] # Preferred ones
|
||||
if desktop_names:
|
||||
return desktop_names[0]
|
||||
desktop_names = [n for n in available_names if n.endswith(".desktop")] # .. otherwise any .desktop
|
||||
if desktop_names:
|
||||
return desktop_names[0]
|
||||
return None
|
||||
|
||||
|
||||
def greeter_setup(self):
|
||||
lightdm_conf_path = os.path.join(
|
||||
self.root_mount_point, "etc/lightdm/lightdm.conf"
|
||||
)
|
||||
lightdm_conf_path = os.path.join(self.root_mount_point, "etc/lightdm/lightdm.conf")
|
||||
greeter_path = self.find_preferred_greeter()
|
||||
|
||||
# configure lightdm-greeter
|
||||
greeter_path = os.path.join(
|
||||
self.root_mount_point, "usr/share/xgreeters"
|
||||
)
|
||||
if greeter_path is not None and os.path.exists(greeter_path):
|
||||
greeter = os.path.basename(os.path.realpath(greeter_path)) # Follow symlinks, hope they are not absolute
|
||||
if greeter.endswith('.desktop'):
|
||||
greeter = greeter[:-8] # Remove ".desktop" from end
|
||||
|
||||
if (os.path.exists(greeter_path)):
|
||||
# configure first found lightdm-greeter
|
||||
for entry in os.listdir(greeter_path):
|
||||
if entry.endswith('.desktop'):
|
||||
greeter = entry.split('.')[0]
|
||||
libcalamares.utils.debug(
|
||||
"found greeter {!s}".format(greeter)
|
||||
)
|
||||
os.system(
|
||||
"sed -i -e \"s/^.*greeter-session=.*"
|
||||
"/greeter-session={!s}/\" {!s}".format(
|
||||
greeter,
|
||||
lightdm_conf_path
|
||||
)
|
||||
)
|
||||
libcalamares.utils.debug(
|
||||
"{!s} configured as greeter.".format(greeter)
|
||||
)
|
||||
break
|
||||
libcalamares.utils.debug("found greeter {!s}".format(greeter))
|
||||
os.system(
|
||||
"sed -i -e \"s/^.*greeter-session=.*"
|
||||
"/greeter-session={!s}/\" {!s}".format(
|
||||
greeter,
|
||||
lightdm_conf_path
|
||||
)
|
||||
)
|
||||
libcalamares.utils.debug("{!s} configured as greeter.".format(greeter))
|
||||
else:
|
||||
if greeter_path is None:
|
||||
libcalamares.utils.error("No greeter found at all, preferred {!s}".format(self.preferred_greeters))
|
||||
else:
|
||||
return (
|
||||
_("Cannot configure LightDM"),
|
||||
_("No LightDM greeter installed.")
|
||||
)
|
||||
|
||||
libcalamares.utils.error("Greeter {!s} selected but file does not exist".format(greeter_path))
|
||||
return (
|
||||
_("Cannot configure LightDM"),
|
||||
_("No LightDM greeter installed.")
|
||||
)
|
||||
|
||||
class DMslim(DisplayManager):
|
||||
name = "slim"
|
||||
|
@ -217,6 +217,12 @@ doReplacePartition( PartitionCoreModule* core, Device* dev, Partition* partition
|
||||
|
||||
cDebug() << "doReplacePartition for device" << partition->partitionPath();
|
||||
|
||||
// Looking up the defaultFsType (which should name a filesystem type)
|
||||
// will log an error and set the type to Unknown if there's something wrong.
|
||||
FileSystem::Type type = FileSystem::Unknown;
|
||||
PartUtils::canonicalFilesystemName( o.defaultFsType, &type );
|
||||
core->partitionLayout().setDefaultFsType( type == FileSystem::Unknown ? FileSystem::Ext4 : type );
|
||||
|
||||
PartitionRole newRoles( partition->roles() );
|
||||
if ( partition->roles().has( PartitionRole::Extended ) )
|
||||
{
|
||||
|
@ -289,11 +289,14 @@ ChoicePage::setupChoices()
|
||||
m_eraseButton->addOptionsComboBox( m_eraseFsTypesChoiceComboBox );
|
||||
|
||||
// Also offer it for "replace
|
||||
auto* box = new QComboBox;
|
||||
box->addItems( m_config->eraseFsTypes() );
|
||||
connect( box, &QComboBox::currentTextChanged, m_config, &Config::setReplaceFilesystemChoice );
|
||||
m_replaceFsTypesChoiceComboBox = new QComboBox;
|
||||
m_replaceFsTypesChoiceComboBox->addItems( m_config->eraseFsTypes() );
|
||||
connect( m_replaceFsTypesChoiceComboBox,
|
||||
&QComboBox::currentTextChanged,
|
||||
m_config,
|
||||
&Config::setReplaceFilesystemChoice );
|
||||
connect( m_config, &Config::replaceModeFilesystemChanged, this, &ChoicePage::onActionChanged );
|
||||
m_replaceButton->addOptionsComboBox( box );
|
||||
m_replaceButton->addOptionsComboBox( m_replaceFsTypesChoiceComboBox );
|
||||
}
|
||||
|
||||
m_itemsLayout->addWidget( m_alongsideButton );
|
||||
@ -450,7 +453,6 @@ ChoicePage::continueApplyDeviceChoice()
|
||||
if ( m_lastSelectedDeviceIndex != m_drivesCombo->currentIndex() )
|
||||
{
|
||||
m_lastSelectedDeviceIndex = m_drivesCombo->currentIndex();
|
||||
m_lastSelectedActionIndex = -1;
|
||||
m_config->setInstallChoice( m_config->initialInstallChoice() );
|
||||
checkInstallChoiceRadioButton( m_config->installChoice() );
|
||||
}
|
||||
@ -484,9 +486,9 @@ ChoicePage::onEraseSwapChoiceChanged()
|
||||
void
|
||||
ChoicePage::applyActionChoice( InstallChoice choice )
|
||||
{
|
||||
cDebug() << "Prev" << m_lastSelectedActionIndex << "InstallChoice" << choice
|
||||
<< Config::installChoiceNames().find( choice );
|
||||
cDebug() << "InstallChoice" << choice << Config::installChoiceNames().find( choice );
|
||||
m_beforePartitionBarsView->selectionModel()->disconnect( SIGNAL( currentRowChanged( QModelIndex, QModelIndex ) ) );
|
||||
auto priorSelection = m_beforePartitionBarsView->selectionModel()->currentIndex();
|
||||
m_beforePartitionBarsView->selectionModel()->clearSelection();
|
||||
m_beforePartitionBarsView->selectionModel()->clearCurrentIndex();
|
||||
|
||||
@ -545,6 +547,12 @@ ChoicePage::applyActionChoice( InstallChoice choice )
|
||||
this,
|
||||
SLOT( onPartitionToReplaceSelected( QModelIndex, QModelIndex ) ),
|
||||
Qt::UniqueConnection );
|
||||
|
||||
// Maintain the selection for replace
|
||||
if ( priorSelection.isValid() )
|
||||
{
|
||||
m_beforePartitionBarsView->selectionModel()->setCurrentIndex( priorSelection, QItemSelectionModel::Select );
|
||||
}
|
||||
break;
|
||||
|
||||
case InstallChoice::Alongside:
|
||||
@ -1741,7 +1749,14 @@ ChoicePage::shouldShowEncryptWidget( Config::InstallChoice choice ) const
|
||||
{
|
||||
// If there are any choices for FS, check it's not ZFS because that doesn't
|
||||
// support the kind of encryption we enable here.
|
||||
const bool suitableFS = m_eraseFsTypesChoiceComboBox ? m_eraseFsTypesChoiceComboBox->currentText() != "zfs" : true;
|
||||
bool suitableFS = true;
|
||||
if ( ( m_eraseFsTypesChoiceComboBox && m_eraseFsTypesChoiceComboBox->isVisible()
|
||||
&& m_eraseFsTypesChoiceComboBox->currentText() == "zfs" )
|
||||
|| ( m_replaceFsTypesChoiceComboBox && m_replaceFsTypesChoiceComboBox->isVisible()
|
||||
&& m_replaceFsTypesChoiceComboBox->currentText() == "zfs" ) )
|
||||
{
|
||||
suitableFS = false;
|
||||
}
|
||||
const bool suitableChoice
|
||||
= choice == InstallChoice::Erase || choice == InstallChoice::Alongside || choice == InstallChoice::Replace;
|
||||
return suitableChoice && m_enableEncryptionWidget && suitableFS;
|
||||
|
@ -152,6 +152,7 @@ private:
|
||||
Calamares::Widgets::PrettyRadioButton* m_somethingElseButton;
|
||||
QComboBox* m_eraseSwapChoiceComboBox = nullptr; // UI, see also Config's swap choice
|
||||
QComboBox* m_eraseFsTypesChoiceComboBox = nullptr; // UI, see also Config's erase-mode FS
|
||||
QComboBox* m_replaceFsTypesChoiceComboBox = nullptr; // UI, see also Config's erase-mode FS
|
||||
|
||||
|
||||
DeviceInfoWidget* m_deviceInfoWidget;
|
||||
@ -166,7 +167,6 @@ private:
|
||||
QPointer< QComboBox > m_efiComboBox;
|
||||
|
||||
int m_lastSelectedDeviceIndex = -1;
|
||||
int m_lastSelectedActionIndex = -1;
|
||||
|
||||
bool m_enableEncryptionWidget = false;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user