2021-01-07 22:30:30 +00:00
|
|
|
# Copyright 2021 Oliver Smith
|
2020-02-20 20:07:28 +00:00
|
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
2017-05-26 20:08:45 +00:00
|
|
|
import logging
|
|
|
|
import os
|
2018-03-17 18:41:41 +00:00
|
|
|
import re
|
2017-05-26 20:08:45 +00:00
|
|
|
import glob
|
2018-03-17 18:41:41 +00:00
|
|
|
import shlex
|
2017-05-26 20:08:45 +00:00
|
|
|
|
|
|
|
import pmb.chroot
|
|
|
|
import pmb.chroot.apk
|
2017-06-09 17:22:25 +00:00
|
|
|
import pmb.chroot.other
|
|
|
|
import pmb.chroot.initfs
|
2017-05-26 20:08:45 +00:00
|
|
|
import pmb.config
|
2020-06-06 21:38:34 +00:00
|
|
|
import pmb.config.pmaports
|
2020-02-26 11:13:26 +00:00
|
|
|
import pmb.helpers.devices
|
2017-05-26 20:08:45 +00:00
|
|
|
import pmb.helpers.run
|
|
|
|
import pmb.install.blockdevice
|
2017-08-24 21:07:36 +00:00
|
|
|
import pmb.install.recovery
|
2021-01-24 09:00:22 +00:00
|
|
|
import pmb.install.ui
|
2017-05-26 20:08:45 +00:00
|
|
|
import pmb.install
|
|
|
|
|
|
|
|
|
2020-06-07 06:44:43 +00:00
|
|
|
def mount_device_rootfs(args, suffix_rootfs, suffix_mount="native"):
|
2017-08-24 21:07:36 +00:00
|
|
|
"""
|
|
|
|
Mount the device rootfs.
|
2020-06-07 06:44:43 +00:00
|
|
|
:param suffix_rootfs: the chroot suffix, where the rootfs that will be
|
|
|
|
installed on the device has been created (e.g.
|
|
|
|
"rootfs_qemu-amd64")
|
|
|
|
:param suffix_mount: the chroot suffix, where the device rootfs will be
|
|
|
|
mounted (e.g. "native")
|
2017-08-24 21:07:36 +00:00
|
|
|
"""
|
2020-06-07 06:44:43 +00:00
|
|
|
mountpoint = f"/mnt/{suffix_rootfs}"
|
|
|
|
pmb.helpers.mount.bind(args, f"{args.work}/chroot_{suffix_rootfs}",
|
|
|
|
f"{args.work}/chroot_{suffix_mount}{mountpoint}")
|
2017-08-03 16:01:00 +00:00
|
|
|
return mountpoint
|
|
|
|
|
|
|
|
|
2020-06-07 06:44:43 +00:00
|
|
|
def get_subpartitions_size(args, suffix):
|
2017-08-18 19:19:48 +00:00
|
|
|
"""
|
2018-05-01 00:18:40 +00:00
|
|
|
Calculate the size of the boot and root subpartition.
|
2017-08-03 16:01:00 +00:00
|
|
|
|
2020-06-07 06:44:43 +00:00
|
|
|
:param suffix: the chroot suffix, e.g. "rootfs_qemu-amd64"
|
2018-05-01 00:18:40 +00:00
|
|
|
:returns: (boot, root) the size of the boot and root
|
2020-06-06 16:39:21 +00:00
|
|
|
partition as integer in MiB
|
2017-08-18 19:19:48 +00:00
|
|
|
"""
|
2020-06-06 16:39:21 +00:00
|
|
|
boot = int(args.boot_size)
|
2017-08-03 16:01:00 +00:00
|
|
|
|
2020-06-02 08:22:07 +00:00
|
|
|
# Estimate root partition size, then add some free space. The size
|
|
|
|
# calculation is not as trivial as one may think, and depending on the
|
|
|
|
# file system etc it seems to be just impossible to get it right.
|
2020-06-07 06:44:43 +00:00
|
|
|
chroot = f"{args.work}/chroot_{suffix}"
|
2020-06-06 16:39:21 +00:00
|
|
|
root = pmb.helpers.other.folder_size(args, chroot) / 1024 / 1024
|
2020-04-12 22:44:53 +00:00
|
|
|
root *= 1.20
|
2020-11-15 16:19:25 +00:00
|
|
|
root += 50 + int(args.extra_space)
|
2020-04-12 22:44:53 +00:00
|
|
|
return (boot, root)
|
2017-08-03 16:01:00 +00:00
|
|
|
|
|
|
|
|
2018-02-24 21:49:10 +00:00
|
|
|
def get_nonfree_packages(args, device):
|
|
|
|
"""
|
|
|
|
Get the non-free packages based on user's choice in "pmbootstrap init" and
|
|
|
|
based on whether there are non-free packages in the APKBUILD or not.
|
|
|
|
|
|
|
|
:returns: list of non-free packages to be installed. Example:
|
|
|
|
["device-nokia-n900-nonfree-firmware"]
|
|
|
|
"""
|
|
|
|
# Read subpackages
|
2021-02-28 19:01:31 +00:00
|
|
|
apkbuild = pmb.parse.apkbuild(args,
|
|
|
|
pmb.helpers.devices.find_path(args, device,
|
|
|
|
'APKBUILD'))
|
2018-02-24 21:49:10 +00:00
|
|
|
subpackages = apkbuild["subpackages"]
|
|
|
|
|
|
|
|
# Check for firmware and userland
|
|
|
|
ret = []
|
|
|
|
prefix = "device-" + device + "-nonfree-"
|
|
|
|
if args.nonfree_firmware and prefix + "firmware" in subpackages:
|
|
|
|
ret += [prefix + "firmware"]
|
|
|
|
if args.nonfree_userland and prefix + "userland" in subpackages:
|
|
|
|
ret += [prefix + "userland"]
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
pmbootstrap init: kernel selection / remove linux-pmos-lts (#1363)
* As discussed in IRC/matrix, we're removing `linux-postmarketos-lts`
for now. The kernel isn't used right now, and we save lots of
maintenance effort with not updating it every week or so.
* new config option `"kernel"` with possible values:
`"downstream", "mainline", "stable"` (downstream is always
`linux-$devicename`)
* ask for the kernel during `pmbootstrap init` if the device package
has kernel subpackages and install it in `_install.py`
* postmarketos-mkinitfs: display note instead of exit with error when
the `deviceinfo_dtb` file is missing (because we expect it to be
missing for downstream kernels)
* device-sony-amami:
* add kernel subpackages for downstream, mainline
* set `deviceinfo_dtb`
* device-qemu-amd64: add kernel subpackages for stable, lts, mainline
* test cases and test data for new functions
* test case that checks all aports for right usage of the feature:
* don't mix specifying kernels in depends *and* subpackages
* 1 kernel in depends is maximum
* kernel subpackages must have a valid name
* Test if devices packages reference at least one kernel
* Remove `_build_device_depends_note()` which informs the user that
`--ignore-depends` can be used with device packages to avoid building
the kernel. The idea was to make the transition easier after a change
we did months ago, and now the kernel doesn't always get built before
building the device package so it's not relevant anymore.
* pmb/chroot/other.py:
* Add autoinstall=True to kernel_flavors_installed(). When the flag
is set, the function makes sure that at least one kernel for the
device is installed.
* Remove kernel_flavor_autodetect() function, wherever it was used,
it has been replaced with kernel_flavors_installed()[0].
* pmb.helpers.frontend.py: remove code to install at least one kernel,
kernel_flavors_installed() takes care of that now.
2018-04-03 23:50:09 +00:00
|
|
|
def get_kernel_package(args, device):
|
|
|
|
"""
|
2018-05-08 21:52:19 +00:00
|
|
|
Get the device's kernel subpackage based on the user's choice in
|
|
|
|
"pmbootstrap init".
|
pmbootstrap init: kernel selection / remove linux-pmos-lts (#1363)
* As discussed in IRC/matrix, we're removing `linux-postmarketos-lts`
for now. The kernel isn't used right now, and we save lots of
maintenance effort with not updating it every week or so.
* new config option `"kernel"` with possible values:
`"downstream", "mainline", "stable"` (downstream is always
`linux-$devicename`)
* ask for the kernel during `pmbootstrap init` if the device package
has kernel subpackages and install it in `_install.py`
* postmarketos-mkinitfs: display note instead of exit with error when
the `deviceinfo_dtb` file is missing (because we expect it to be
missing for downstream kernels)
* device-sony-amami:
* add kernel subpackages for downstream, mainline
* set `deviceinfo_dtb`
* device-qemu-amd64: add kernel subpackages for stable, lts, mainline
* test cases and test data for new functions
* test case that checks all aports for right usage of the feature:
* don't mix specifying kernels in depends *and* subpackages
* 1 kernel in depends is maximum
* kernel subpackages must have a valid name
* Test if devices packages reference at least one kernel
* Remove `_build_device_depends_note()` which informs the user that
`--ignore-depends` can be used with device packages to avoid building
the kernel. The idea was to make the transition easier after a change
we did months ago, and now the kernel doesn't always get built before
building the device package so it's not relevant anymore.
* pmb/chroot/other.py:
* Add autoinstall=True to kernel_flavors_installed(). When the flag
is set, the function makes sure that at least one kernel for the
device is installed.
* Remove kernel_flavor_autodetect() function, wherever it was used,
it has been replaced with kernel_flavors_installed()[0].
* pmb.helpers.frontend.py: remove code to install at least one kernel,
kernel_flavors_installed() takes care of that now.
2018-04-03 23:50:09 +00:00
|
|
|
|
2018-05-08 21:52:19 +00:00
|
|
|
:param device: code name, e.g. "sony-amami"
|
|
|
|
:returns: [] or the package in a list, e.g.
|
|
|
|
["device-sony-amami-kernel-mainline"]
|
pmbootstrap init: kernel selection / remove linux-pmos-lts (#1363)
* As discussed in IRC/matrix, we're removing `linux-postmarketos-lts`
for now. The kernel isn't used right now, and we save lots of
maintenance effort with not updating it every week or so.
* new config option `"kernel"` with possible values:
`"downstream", "mainline", "stable"` (downstream is always
`linux-$devicename`)
* ask for the kernel during `pmbootstrap init` if the device package
has kernel subpackages and install it in `_install.py`
* postmarketos-mkinitfs: display note instead of exit with error when
the `deviceinfo_dtb` file is missing (because we expect it to be
missing for downstream kernels)
* device-sony-amami:
* add kernel subpackages for downstream, mainline
* set `deviceinfo_dtb`
* device-qemu-amd64: add kernel subpackages for stable, lts, mainline
* test cases and test data for new functions
* test case that checks all aports for right usage of the feature:
* don't mix specifying kernels in depends *and* subpackages
* 1 kernel in depends is maximum
* kernel subpackages must have a valid name
* Test if devices packages reference at least one kernel
* Remove `_build_device_depends_note()` which informs the user that
`--ignore-depends` can be used with device packages to avoid building
the kernel. The idea was to make the transition easier after a change
we did months ago, and now the kernel doesn't always get built before
building the device package so it's not relevant anymore.
* pmb/chroot/other.py:
* Add autoinstall=True to kernel_flavors_installed(). When the flag
is set, the function makes sure that at least one kernel for the
device is installed.
* Remove kernel_flavor_autodetect() function, wherever it was used,
it has been replaced with kernel_flavors_installed()[0].
* pmb.helpers.frontend.py: remove code to install at least one kernel,
kernel_flavors_installed() takes care of that now.
2018-04-03 23:50:09 +00:00
|
|
|
"""
|
2018-05-08 21:52:19 +00:00
|
|
|
# Empty list: single kernel devices / "none" selected
|
pmbootstrap init: kernel selection / remove linux-pmos-lts (#1363)
* As discussed in IRC/matrix, we're removing `linux-postmarketos-lts`
for now. The kernel isn't used right now, and we save lots of
maintenance effort with not updating it every week or so.
* new config option `"kernel"` with possible values:
`"downstream", "mainline", "stable"` (downstream is always
`linux-$devicename`)
* ask for the kernel during `pmbootstrap init` if the device package
has kernel subpackages and install it in `_install.py`
* postmarketos-mkinitfs: display note instead of exit with error when
the `deviceinfo_dtb` file is missing (because we expect it to be
missing for downstream kernels)
* device-sony-amami:
* add kernel subpackages for downstream, mainline
* set `deviceinfo_dtb`
* device-qemu-amd64: add kernel subpackages for stable, lts, mainline
* test cases and test data for new functions
* test case that checks all aports for right usage of the feature:
* don't mix specifying kernels in depends *and* subpackages
* 1 kernel in depends is maximum
* kernel subpackages must have a valid name
* Test if devices packages reference at least one kernel
* Remove `_build_device_depends_note()` which informs the user that
`--ignore-depends` can be used with device packages to avoid building
the kernel. The idea was to make the transition easier after a change
we did months ago, and now the kernel doesn't always get built before
building the device package so it's not relevant anymore.
* pmb/chroot/other.py:
* Add autoinstall=True to kernel_flavors_installed(). When the flag
is set, the function makes sure that at least one kernel for the
device is installed.
* Remove kernel_flavor_autodetect() function, wherever it was used,
it has been replaced with kernel_flavors_installed()[0].
* pmb.helpers.frontend.py: remove code to install at least one kernel,
kernel_flavors_installed() takes care of that now.
2018-04-03 23:50:09 +00:00
|
|
|
kernels = pmb.parse._apkbuild.kernels(args, device)
|
|
|
|
if not kernels or args.kernel == "none":
|
|
|
|
return []
|
|
|
|
|
|
|
|
# Sanity check
|
|
|
|
if args.kernel not in kernels:
|
|
|
|
raise RuntimeError("Selected kernel (" + args.kernel + ") is not"
|
2021-01-31 11:53:23 +00:00
|
|
|
" valid for device " + device + ". Please"
|
pmbootstrap init: kernel selection / remove linux-pmos-lts (#1363)
* As discussed in IRC/matrix, we're removing `linux-postmarketos-lts`
for now. The kernel isn't used right now, and we save lots of
maintenance effort with not updating it every week or so.
* new config option `"kernel"` with possible values:
`"downstream", "mainline", "stable"` (downstream is always
`linux-$devicename`)
* ask for the kernel during `pmbootstrap init` if the device package
has kernel subpackages and install it in `_install.py`
* postmarketos-mkinitfs: display note instead of exit with error when
the `deviceinfo_dtb` file is missing (because we expect it to be
missing for downstream kernels)
* device-sony-amami:
* add kernel subpackages for downstream, mainline
* set `deviceinfo_dtb`
* device-qemu-amd64: add kernel subpackages for stable, lts, mainline
* test cases and test data for new functions
* test case that checks all aports for right usage of the feature:
* don't mix specifying kernels in depends *and* subpackages
* 1 kernel in depends is maximum
* kernel subpackages must have a valid name
* Test if devices packages reference at least one kernel
* Remove `_build_device_depends_note()` which informs the user that
`--ignore-depends` can be used with device packages to avoid building
the kernel. The idea was to make the transition easier after a change
we did months ago, and now the kernel doesn't always get built before
building the device package so it's not relevant anymore.
* pmb/chroot/other.py:
* Add autoinstall=True to kernel_flavors_installed(). When the flag
is set, the function makes sure that at least one kernel for the
device is installed.
* Remove kernel_flavor_autodetect() function, wherever it was used,
it has been replaced with kernel_flavors_installed()[0].
* pmb.helpers.frontend.py: remove code to install at least one kernel,
kernel_flavors_installed() takes care of that now.
2018-04-03 23:50:09 +00:00
|
|
|
" run 'pmbootstrap init' to select a valid kernel.")
|
|
|
|
|
2018-05-08 21:52:19 +00:00
|
|
|
# Selected kernel subpackage
|
|
|
|
return ["device-" + device + "-kernel-" + args.kernel]
|
pmbootstrap init: kernel selection / remove linux-pmos-lts (#1363)
* As discussed in IRC/matrix, we're removing `linux-postmarketos-lts`
for now. The kernel isn't used right now, and we save lots of
maintenance effort with not updating it every week or so.
* new config option `"kernel"` with possible values:
`"downstream", "mainline", "stable"` (downstream is always
`linux-$devicename`)
* ask for the kernel during `pmbootstrap init` if the device package
has kernel subpackages and install it in `_install.py`
* postmarketos-mkinitfs: display note instead of exit with error when
the `deviceinfo_dtb` file is missing (because we expect it to be
missing for downstream kernels)
* device-sony-amami:
* add kernel subpackages for downstream, mainline
* set `deviceinfo_dtb`
* device-qemu-amd64: add kernel subpackages for stable, lts, mainline
* test cases and test data for new functions
* test case that checks all aports for right usage of the feature:
* don't mix specifying kernels in depends *and* subpackages
* 1 kernel in depends is maximum
* kernel subpackages must have a valid name
* Test if devices packages reference at least one kernel
* Remove `_build_device_depends_note()` which informs the user that
`--ignore-depends` can be used with device packages to avoid building
the kernel. The idea was to make the transition easier after a change
we did months ago, and now the kernel doesn't always get built before
building the device package so it's not relevant anymore.
* pmb/chroot/other.py:
* Add autoinstall=True to kernel_flavors_installed(). When the flag
is set, the function makes sure that at least one kernel for the
device is installed.
* Remove kernel_flavor_autodetect() function, wherever it was used,
it has been replaced with kernel_flavors_installed()[0].
* pmb.helpers.frontend.py: remove code to install at least one kernel,
kernel_flavors_installed() takes care of that now.
2018-04-03 23:50:09 +00:00
|
|
|
|
|
|
|
|
2020-06-07 06:44:43 +00:00
|
|
|
def copy_files_from_chroot(args, suffix):
|
2017-08-18 19:19:48 +00:00
|
|
|
"""
|
|
|
|
Copy all files from the rootfs chroot to /mnt/install, except
|
|
|
|
for the home folder (because /home will contain some empty
|
|
|
|
mountpoint folders).
|
2020-06-07 06:44:43 +00:00
|
|
|
|
|
|
|
:param suffix: the chroot suffix, e.g. "rootfs_qemu-amd64"
|
2017-08-18 19:19:48 +00:00
|
|
|
"""
|
2017-08-03 16:01:00 +00:00
|
|
|
# Mount the device rootfs
|
2020-06-07 06:44:43 +00:00
|
|
|
logging.info(f"(native) copy {suffix} to /mnt/install/")
|
|
|
|
mountpoint = mount_device_rootfs(args, suffix)
|
2017-08-18 19:19:48 +00:00
|
|
|
mountpoint_outside = args.work + "/chroot_native" + mountpoint
|
2017-05-26 20:08:45 +00:00
|
|
|
|
2020-01-20 10:36:14 +00:00
|
|
|
# Remove empty qemu-user binary stub (where the binary was bind-mounted)
|
|
|
|
arch_qemu = pmb.parse.arch.alpine_to_qemu(args.deviceinfo["arch"])
|
|
|
|
qemu_binary = mountpoint_outside + "/usr/bin/qemu-" + arch_qemu + "-static"
|
|
|
|
if os.path.exists(qemu_binary):
|
|
|
|
pmb.helpers.run.root(args, ["rm", qemu_binary])
|
|
|
|
|
2020-11-27 19:45:22 +00:00
|
|
|
# Remove apk progress fifo
|
|
|
|
fifo = f"{args.work}/chroot_{suffix}/tmp/apk_progress_fifo"
|
|
|
|
if os.path.exists(fifo):
|
|
|
|
pmb.helpers.run.root(args, ["rm", fifo])
|
|
|
|
|
2017-08-18 19:19:48 +00:00
|
|
|
# Get all folders inside the device rootfs (except for home)
|
2017-05-26 20:08:45 +00:00
|
|
|
folders = []
|
2017-08-18 19:19:48 +00:00
|
|
|
for path in glob.glob(mountpoint_outside + "/*"):
|
|
|
|
if path.endswith("/home"):
|
|
|
|
continue
|
2017-05-26 20:08:45 +00:00
|
|
|
folders += [os.path.basename(path)]
|
|
|
|
|
2018-01-28 23:25:21 +00:00
|
|
|
# Update or copy all files
|
|
|
|
if args.rsync:
|
|
|
|
pmb.chroot.apk.install(args, ["rsync"])
|
|
|
|
rsync_flags = "-a"
|
|
|
|
if args.verbose:
|
|
|
|
rsync_flags += "vP"
|
2021-02-28 19:01:31 +00:00
|
|
|
pmb.chroot.root(args, ["rsync", rsync_flags, "--delete"] + folders +
|
|
|
|
["/mnt/install/"], working_dir=mountpoint)
|
2018-01-28 23:25:21 +00:00
|
|
|
pmb.chroot.root(args, ["rm", "-rf", "/mnt/install/home"])
|
|
|
|
else:
|
|
|
|
pmb.chroot.root(args, ["cp", "-a"] + folders + ["/mnt/install/"],
|
|
|
|
working_dir=mountpoint)
|
2017-05-26 20:08:45 +00:00
|
|
|
|
|
|
|
|
2018-02-01 22:44:20 +00:00
|
|
|
def create_home_from_skel(args):
|
2017-08-18 19:19:48 +00:00
|
|
|
"""
|
2018-02-01 22:44:20 +00:00
|
|
|
Create /home/{user} from /etc/skel
|
2017-08-18 19:19:48 +00:00
|
|
|
"""
|
|
|
|
rootfs = args.work + "/chroot_native/mnt/install"
|
2017-10-12 20:08:10 +00:00
|
|
|
homedir = rootfs + "/home/" + args.user
|
2017-10-03 18:10:28 +00:00
|
|
|
pmb.helpers.run.root(args, ["mkdir", rootfs + "/home"])
|
2020-12-07 07:56:41 +00:00
|
|
|
if os.path.exists(f"{rootfs}/etc/skel"):
|
|
|
|
pmb.helpers.run.root(args, ["cp", "-a", f"{rootfs}/etc/skel", homedir])
|
|
|
|
else:
|
|
|
|
pmb.helpers.run.root(args, ["mkdir", homedir])
|
2018-08-02 20:10:56 +00:00
|
|
|
pmb.helpers.run.root(args, ["chown", "-R", "10000", homedir])
|
2017-10-12 20:08:10 +00:00
|
|
|
|
|
|
|
|
2018-02-01 22:44:20 +00:00
|
|
|
def configure_apk(args):
|
|
|
|
"""
|
2020-06-22 11:40:30 +00:00
|
|
|
Copy over all official keys, and the keys used to compile local packages
|
|
|
|
(unless --no-local-pkgs is set). Then disable the /mnt/pmbootstrap-packages
|
|
|
|
repository.
|
2018-02-01 22:44:20 +00:00
|
|
|
"""
|
2020-06-22 11:40:30 +00:00
|
|
|
# Official keys
|
|
|
|
pattern = f"{pmb.config.apk_keys_path}/*.pub"
|
|
|
|
|
|
|
|
# Official keys + local keys
|
|
|
|
if args.install_local_pkgs:
|
|
|
|
pattern = f"{args.work}/config_apk_keys/*.pub"
|
|
|
|
|
2018-02-01 22:44:20 +00:00
|
|
|
# Copy over keys
|
|
|
|
rootfs = args.work + "/chroot_native/mnt/install"
|
2020-06-22 11:40:30 +00:00
|
|
|
for key in glob.glob(pattern):
|
2018-02-01 22:44:20 +00:00
|
|
|
pmb.helpers.run.root(args, ["cp", key, rootfs + "/etc/apk/keys/"])
|
|
|
|
|
|
|
|
# Disable pmbootstrap repository
|
2019-07-26 21:45:24 +00:00
|
|
|
pmb.helpers.run.root(args, ["sed", "-i", r"/\/mnt\/pmbootstrap-packages/d",
|
2018-06-09 06:52:24 +00:00
|
|
|
rootfs + "/etc/apk/repositories"])
|
2018-02-01 22:44:20 +00:00
|
|
|
pmb.helpers.run.user(args, ["cat", rootfs + "/etc/apk/repositories"])
|
|
|
|
|
|
|
|
|
2017-10-12 20:08:10 +00:00
|
|
|
def set_user(args):
|
|
|
|
"""
|
2018-08-02 20:10:56 +00:00
|
|
|
Create user with UID 10000 if it doesn't exist.
|
|
|
|
Usually the ID for the first user created is 1000, but higher ID is
|
|
|
|
chosen here to avoid conflict with Android UIDs/GIDs.
|
|
|
|
|
2017-10-12 20:08:10 +00:00
|
|
|
"""
|
|
|
|
suffix = "rootfs_" + args.device
|
|
|
|
if not pmb.chroot.user_exists(args, args.user, suffix):
|
2018-08-02 20:10:56 +00:00
|
|
|
pmb.chroot.root(args, ["adduser", "-D", "-u", "10000", args.user],
|
2017-10-12 20:08:10 +00:00
|
|
|
suffix)
|
2021-01-24 09:03:51 +00:00
|
|
|
groups = pmb.install.ui.get_groups(args) + pmb.config.install_user_groups
|
|
|
|
for group in groups:
|
2021-01-24 09:01:16 +00:00
|
|
|
pmb.chroot.root(args, ["addgroup", "-S", group], suffix,
|
|
|
|
check=False)
|
|
|
|
pmb.chroot.root(args, ["addgroup", args.user, group], suffix)
|
2017-05-26 20:08:45 +00:00
|
|
|
|
|
|
|
|
2021-02-08 21:46:37 +00:00
|
|
|
def setup_login(args, suffix):
|
2017-05-26 20:08:45 +00:00
|
|
|
"""
|
2021-02-28 19:01:31 +00:00
|
|
|
Loop until the password for user has been set successfully, and disable
|
|
|
|
root login.
|
2021-02-08 21:46:37 +00:00
|
|
|
|
|
|
|
:param suffix: of the chroot, where passwd will be execute (either the
|
|
|
|
f"rootfs_{args.device}", or f"installer_{args.device}")
|
2017-05-26 20:08:45 +00:00
|
|
|
"""
|
2020-06-30 22:14:08 +00:00
|
|
|
if not args.on_device_installer:
|
|
|
|
# User password
|
|
|
|
logging.info(" *** SET LOGIN PASSWORD FOR: '" + args.user + "' ***")
|
|
|
|
while True:
|
|
|
|
try:
|
|
|
|
pmb.chroot.root(args, ["passwd", args.user], suffix,
|
|
|
|
output="interactive")
|
|
|
|
break
|
|
|
|
except RuntimeError:
|
|
|
|
logging.info("WARNING: Failed to set the password. Try it"
|
|
|
|
" one more time.")
|
|
|
|
pass
|
2017-05-26 20:08:45 +00:00
|
|
|
|
2017-12-02 08:19:11 +00:00
|
|
|
# Disable root login
|
|
|
|
pmb.chroot.root(args, ["passwd", "-l", "root"], suffix)
|
|
|
|
|
2017-05-26 20:08:45 +00:00
|
|
|
|
2018-04-08 14:12:01 +00:00
|
|
|
def copy_ssh_keys(args):
|
2017-08-16 17:30:38 +00:00
|
|
|
"""
|
2018-04-08 14:12:01 +00:00
|
|
|
If requested, copy user's SSH public keys to the device if they exist
|
2017-08-16 17:30:38 +00:00
|
|
|
"""
|
2018-04-08 14:12:01 +00:00
|
|
|
if not args.ssh_keys:
|
|
|
|
return
|
2017-09-21 17:11:20 +00:00
|
|
|
keys = []
|
2018-04-08 14:12:01 +00:00
|
|
|
for key in glob.glob(os.path.expanduser("~/.ssh/id_*.pub")):
|
|
|
|
with open(key, "r") as infile:
|
|
|
|
keys += infile.readlines()
|
2017-09-21 17:11:20 +00:00
|
|
|
|
|
|
|
if not len(keys):
|
2021-02-28 19:01:31 +00:00
|
|
|
logging.info("NOTE: Public SSH keys not found. Since no SSH keys "
|
|
|
|
"were copied, you will need to use SSH password "
|
|
|
|
"authentication!")
|
2017-09-21 17:11:20 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
authorized_keys = args.work + "/chroot_native/tmp/authorized_keys"
|
|
|
|
outfile = open(authorized_keys, "w")
|
|
|
|
for key in keys:
|
|
|
|
outfile.write("%s" % key)
|
|
|
|
outfile.close()
|
|
|
|
|
2021-02-28 19:01:31 +00:00
|
|
|
target = f"{args.work}/chroot_native/mnt/install/home/{args.user}/.ssh"
|
2017-09-21 17:11:20 +00:00
|
|
|
pmb.helpers.run.root(args, ["mkdir", target])
|
|
|
|
pmb.helpers.run.root(args, ["chmod", "700", target])
|
2021-02-28 19:01:31 +00:00
|
|
|
pmb.helpers.run.root(args, ["cp", authorized_keys, target +
|
|
|
|
"/authorized_keys"])
|
2017-09-21 17:11:20 +00:00
|
|
|
pmb.helpers.run.root(args, ["rm", authorized_keys])
|
2018-08-02 20:10:56 +00:00
|
|
|
pmb.helpers.run.root(args, ["chown", "-R", "10000:10000", target])
|
2017-08-16 17:30:38 +00:00
|
|
|
|
|
|
|
|
2017-08-19 21:40:20 +00:00
|
|
|
def setup_keymap(args):
|
|
|
|
"""
|
|
|
|
Set the keymap with the setup-keymap utility if the device requires it
|
|
|
|
"""
|
|
|
|
suffix = "rootfs_" + args.device
|
|
|
|
info = pmb.parse.deviceinfo(args, device=args.device)
|
|
|
|
if "keymaps" not in info or info["keymaps"].strip() == "":
|
|
|
|
logging.info("NOTE: No valid keymap specified for device")
|
|
|
|
return
|
|
|
|
options = info["keymaps"].split(' ')
|
|
|
|
if (args.keymap != "" and
|
|
|
|
args.keymap is not None and
|
|
|
|
args.keymap in options):
|
|
|
|
layout, variant = args.keymap.split("/")
|
2018-07-14 01:13:28 +00:00
|
|
|
pmb.chroot.root(args, ["setup-keymap", layout, variant], suffix,
|
|
|
|
output="interactive")
|
2019-11-18 23:45:10 +00:00
|
|
|
|
|
|
|
# Check xorg config
|
2020-08-11 23:16:09 +00:00
|
|
|
config = None
|
|
|
|
if os.path.exists(f"{args.work}/chroot_{suffix}/etc/X11/xorg.conf.d"):
|
|
|
|
config = pmb.chroot.root(args, ["grep", "-rl", "XkbLayout",
|
|
|
|
"/etc/X11/xorg.conf.d/"],
|
|
|
|
suffix, check=False, output_return=True)
|
2019-11-18 23:45:10 +00:00
|
|
|
if config:
|
2020-08-31 14:02:04 +00:00
|
|
|
# Nokia n900 (RX-51) randomly merges some keymaps so we
|
|
|
|
# have to specify a composite keymap for a few countries. See:
|
|
|
|
# https://gitlab.freedesktop.org/xkeyboard-config/xkeyboard-config/-/blob/master/symbols/nokia_vndr/rx-51
|
|
|
|
if variant == "rx51_fi" or variant == "rx51_se":
|
|
|
|
layout = "fise"
|
|
|
|
if variant == "rx51_da" or variant == "rx51_no":
|
|
|
|
layout = "dano"
|
|
|
|
if variant == "rx51_pt" or variant == "rx51_es":
|
|
|
|
layout = "ptes"
|
2019-11-18 23:45:10 +00:00
|
|
|
# Multiple files can contain the keyboard layout, take last
|
|
|
|
config = config.splitlines()[-1]
|
|
|
|
old_text = "Option *\\\"XkbLayout\\\" *\\\".*\\\""
|
|
|
|
new_text = "Option \\\"XkbLayout\\\" \\\"" + layout + "\\\""
|
2021-02-28 19:01:31 +00:00
|
|
|
pmb.chroot.root(args, ["sed", "-i", "s/" + old_text + "/" +
|
|
|
|
new_text + "/", config], suffix)
|
2017-08-19 21:40:20 +00:00
|
|
|
else:
|
|
|
|
logging.info("NOTE: No valid keymap specified for device")
|
|
|
|
|
|
|
|
|
2018-03-17 18:41:41 +00:00
|
|
|
def setup_hostname(args):
|
|
|
|
"""
|
|
|
|
Set the hostname and update localhost address in /etc/hosts
|
|
|
|
"""
|
|
|
|
# Default to device name
|
|
|
|
hostname = args.hostname
|
|
|
|
if not hostname:
|
|
|
|
hostname = args.device
|
|
|
|
|
|
|
|
if not pmb.helpers.other.validate_hostname(hostname):
|
|
|
|
raise RuntimeError("Hostname '" + hostname + "' is not valid, please"
|
|
|
|
" run 'pmbootstrap init' to configure it.")
|
|
|
|
|
|
|
|
suffix = "rootfs_" + args.device
|
2020-05-15 17:15:04 +00:00
|
|
|
# Generate /etc/hostname
|
2018-03-17 18:41:41 +00:00
|
|
|
pmb.chroot.root(args, ["sh", "-c", "echo " + shlex.quote(hostname) +
|
2018-06-09 06:52:24 +00:00
|
|
|
" > /etc/hostname"], suffix)
|
2020-05-15 17:15:04 +00:00
|
|
|
# Update /etc/hosts
|
2019-07-26 21:45:24 +00:00
|
|
|
regex = (r"s/^127\.0\.0\.1.*/127.0.0.1\t" + re.escape(hostname) +
|
2018-03-17 18:41:41 +00:00
|
|
|
" localhost.localdomain localhost/")
|
|
|
|
pmb.chroot.root(args, ["sed", "-i", "-e", regex, "/etc/hosts"], suffix)
|
|
|
|
|
|
|
|
|
2021-02-13 11:00:43 +00:00
|
|
|
def disable_sshd(args):
|
|
|
|
if not args.no_sshd:
|
|
|
|
return
|
|
|
|
|
|
|
|
# check=False: rc-update doesn't exit with 0 if already disabled
|
|
|
|
suffix = f"rootfs_{args.device}"
|
|
|
|
pmb.chroot.root(args, ["rc-update", "del", "sshd", "default"], suffix,
|
|
|
|
check=False)
|
|
|
|
|
|
|
|
# Verify that it's gone
|
|
|
|
sshd_files = pmb.helpers.run.root(
|
|
|
|
args, ["find", "-name", "sshd"], output_return=True,
|
|
|
|
working_dir=f"{args.work}/chroot_{suffix}/etc/runlevels")
|
|
|
|
if sshd_files:
|
|
|
|
raise RuntimeError(f"Failed to disable sshd service: {sshd_files}")
|
|
|
|
|
|
|
|
|
|
|
|
def print_sshd_info(args):
|
2021-02-13 11:51:28 +00:00
|
|
|
logging.info("") # make the note stand out
|
2021-02-13 11:00:43 +00:00
|
|
|
logging.info("*** SSH DAEMON INFORMATION ***")
|
|
|
|
|
|
|
|
if not args.ondev_no_rootfs:
|
|
|
|
if args.no_sshd:
|
|
|
|
logging.info("SSH daemon is disabled (--no-sshd).")
|
|
|
|
else:
|
|
|
|
logging.info("SSH daemon is enabled (disable with --no-sshd).")
|
|
|
|
logging.info(f"Login as '{args.user}' with the password given"
|
|
|
|
" during installation.")
|
|
|
|
|
|
|
|
if args.on_device_installer:
|
|
|
|
# We don't disable sshd in the installer OS. If the device is reachable
|
|
|
|
# on the network by default (e.g. Raspberry Pi), one can lock down the
|
|
|
|
# installer OS down by disabling the debug user (see wiki page).
|
|
|
|
logging.info("SSH daemon is enabled in the installer OS, to allow"
|
|
|
|
" debugging the installer image.")
|
|
|
|
logging.info("More info: https://postmarketos.org/ondev-debug")
|
|
|
|
|
|
|
|
|
2020-10-06 15:44:56 +00:00
|
|
|
def embed_firmware(args, suffix):
|
2019-01-09 05:42:37 +00:00
|
|
|
"""
|
|
|
|
This method will embed firmware, located at /usr/share, that are specified
|
|
|
|
by the "sd_embed_firmware" deviceinfo parameter into the SD card image
|
|
|
|
(e.g. u-boot). Binaries that would overwrite the first partition are not
|
|
|
|
accepted, and if multiple binaries are specified then they will be checked
|
|
|
|
for collisions with each other.
|
2020-10-06 15:44:56 +00:00
|
|
|
|
|
|
|
:param suffix: of the chroot, which holds the firmware files (either the
|
|
|
|
f"rootfs_{args.device}", or f"installer_{args.device}")
|
2019-01-09 05:42:37 +00:00
|
|
|
"""
|
|
|
|
if not args.deviceinfo["sd_embed_firmware"]:
|
|
|
|
return
|
2018-09-11 07:05:04 +00:00
|
|
|
|
2019-01-09 05:42:37 +00:00
|
|
|
step = 1024
|
|
|
|
if args.deviceinfo["sd_embed_firmware_step_size"]:
|
|
|
|
try:
|
|
|
|
step = int(args.deviceinfo["sd_embed_firmware_step_size"])
|
|
|
|
except ValueError:
|
|
|
|
raise RuntimeError("Value for "
|
|
|
|
"deviceinfo_sd_embed_firmware_step_size "
|
|
|
|
"is not valid: {}".format(step))
|
|
|
|
|
2020-10-06 15:44:56 +00:00
|
|
|
device_rootfs = mount_device_rootfs(args, suffix)
|
2019-01-09 05:42:37 +00:00
|
|
|
binaries = args.deviceinfo["sd_embed_firmware"].split(",")
|
|
|
|
|
|
|
|
# Perform three checks prior to writing binaries to disk: 1) that binaries
|
|
|
|
# exist, 2) that binaries do not extend into the first partition, 3) that
|
2019-06-25 07:18:00 +00:00
|
|
|
# binaries do not overlap each other
|
2019-01-09 05:42:37 +00:00
|
|
|
binary_ranges = {}
|
|
|
|
binary_list = []
|
|
|
|
for binary_offset in binaries:
|
|
|
|
binary, offset = binary_offset.split(':')
|
|
|
|
try:
|
|
|
|
offset = int(offset)
|
|
|
|
except ValueError:
|
|
|
|
raise RuntimeError("Value for firmware binary offset is "
|
|
|
|
"not valid: {}".format(offset))
|
2020-10-06 15:44:56 +00:00
|
|
|
binary_path = os.path.join(args.work, f"chroot_{suffix}", "usr/share",
|
|
|
|
binary)
|
2019-01-09 05:42:37 +00:00
|
|
|
if not os.path.exists(binary_path):
|
|
|
|
raise RuntimeError("The following firmware binary does not "
|
2020-10-06 15:44:56 +00:00
|
|
|
f"exist in the {suffix} chroot: "
|
|
|
|
f"/usr/share/{binary}")
|
2019-01-09 05:42:37 +00:00
|
|
|
# Insure that embedding the firmware will not overrun the
|
|
|
|
# first partition
|
2020-01-12 03:24:37 +00:00
|
|
|
boot_part_start = args.deviceinfo["boot_part_start"] or "2048"
|
|
|
|
max_size = (int(boot_part_start) * 512) - (offset * step)
|
2019-01-09 05:42:37 +00:00
|
|
|
binary_size = os.path.getsize(binary_path)
|
|
|
|
if binary_size > max_size:
|
|
|
|
raise RuntimeError("The firmware is too big to embed in the "
|
|
|
|
"disk image {}B > {}B".format(binary_size,
|
|
|
|
max_size))
|
|
|
|
# Insure that the firmware does not conflict with any other firmware
|
|
|
|
# that will be embedded
|
|
|
|
binary_start = offset * step
|
|
|
|
binary_end = binary_start + binary_size
|
|
|
|
for start, end in binary_ranges.items():
|
|
|
|
if ((binary_start >= start and binary_start <= end) or
|
|
|
|
(binary_end >= start and binary_end <= end)):
|
|
|
|
raise RuntimeError("The firmware overlaps with at least one "
|
|
|
|
"other firmware image: {}".format(binary))
|
|
|
|
binary_ranges[binary_start] = binary_end
|
|
|
|
binary_list.append((binary, offset))
|
|
|
|
|
|
|
|
# Write binaries to disk
|
|
|
|
for binary, offset in binary_list:
|
|
|
|
binary_file = os.path.join("/usr/share", binary)
|
|
|
|
logging.info("Embed firmware {} in the SD card image at offset {} with"
|
|
|
|
" step size {}".format(binary, offset, step))
|
|
|
|
filename = os.path.join(device_rootfs, binary_file.lstrip("/"))
|
|
|
|
pmb.chroot.root(args, ["dd", "if=" + filename, "of=/dev/install",
|
|
|
|
"bs=" + str(step), "seek=" + str(offset)])
|
2018-09-11 07:05:04 +00:00
|
|
|
|
|
|
|
|
2020-07-07 11:16:48 +00:00
|
|
|
def sanity_check_sdcard(args):
|
|
|
|
device = args.sdcard
|
2019-03-30 14:07:23 +00:00
|
|
|
device_name = os.path.basename(device)
|
2020-03-22 10:09:04 +00:00
|
|
|
if not os.path.exists(device):
|
2021-02-28 19:01:31 +00:00
|
|
|
raise RuntimeError(f"{device} doesn't exist, is the sdcard plugged?")
|
2019-03-30 14:07:23 +00:00
|
|
|
if os.path.isdir('/sys/class/block/{}'.format(device_name)):
|
|
|
|
with open('/sys/class/block/{}/ro'.format(device_name), 'r') as handle:
|
|
|
|
ro = handle.read()
|
|
|
|
if ro == '1\n':
|
2021-02-28 19:01:31 +00:00
|
|
|
raise RuntimeError(f"{device} is read-only, is the sdcard locked?")
|
2019-03-30 14:07:23 +00:00
|
|
|
|
|
|
|
|
2020-07-07 11:16:48 +00:00
|
|
|
def sanity_check_sdcard_size(args):
|
|
|
|
device = args.sdcard
|
|
|
|
devpath = os.path.realpath(device)
|
|
|
|
sysfs = '/sys/class/block/{}/size'.format(devpath.replace('/dev/', ''))
|
|
|
|
if not os.path.isfile(sysfs):
|
|
|
|
# This is a best-effort sanity check, continue if it's not checkable
|
|
|
|
return
|
|
|
|
|
|
|
|
with open(sysfs) as handle:
|
|
|
|
raw = handle.read()
|
|
|
|
|
|
|
|
# Size is in 512-byte blocks
|
|
|
|
size = int(raw.strip())
|
|
|
|
human = "{:.2f} GiB".format(size / 2 / 1024 / 1024)
|
|
|
|
|
|
|
|
# Warn if the size is larger than 100GiB
|
|
|
|
if size > (100 * 2 * 1024 * 1024):
|
2021-02-28 19:01:31 +00:00
|
|
|
if not pmb.helpers.cli.confirm(args,
|
|
|
|
f"WARNING: The target disk ({devpath}) "
|
|
|
|
"is larger than a usual SD card "
|
|
|
|
"(>100GiB). Are you sure you want to "
|
|
|
|
f"overwrite this {human} disk?",
|
|
|
|
no_assumptions=True):
|
2020-07-07 11:16:48 +00:00
|
|
|
raise RuntimeError("Aborted.")
|
|
|
|
|
|
|
|
|
2021-01-24 08:34:42 +00:00
|
|
|
def get_ondev_pkgver(args):
|
2020-06-29 18:40:02 +00:00
|
|
|
arch = args.deviceinfo["arch"]
|
|
|
|
package = pmb.helpers.package.get(args, "postmarketos-ondev", arch)
|
2021-01-24 08:34:42 +00:00
|
|
|
return package["version"].split("-r")[0]
|
|
|
|
|
|
|
|
|
|
|
|
def sanity_check_ondev_version(args):
|
|
|
|
ver_pkg = get_ondev_pkgver(args)
|
2020-06-29 18:40:02 +00:00
|
|
|
ver_min = pmb.config.ondev_min_version
|
|
|
|
if pmb.parse.version.compare(ver_pkg, ver_min) == -1:
|
|
|
|
raise RuntimeError("This version of pmbootstrap requires"
|
|
|
|
f" postmarketos-ondev version {ver_min} or"
|
|
|
|
" higher. The postmarketos-ondev found in pmaports"
|
|
|
|
f" / in the binary packages has version {ver_pkg}.")
|
|
|
|
|
|
|
|
|
2020-11-18 18:37:11 +00:00
|
|
|
def install_system_image(args, size_reserve, suffix, step, steps,
|
2020-12-18 21:14:13 +00:00
|
|
|
boot_label="pmOS_boot", root_label="pmOS_root",
|
|
|
|
split=False, sdcard=None):
|
2020-06-06 17:05:11 +00:00
|
|
|
"""
|
|
|
|
:param size_reserve: empty partition between root and boot in MiB (pma#463)
|
2020-06-07 06:44:43 +00:00
|
|
|
:param suffix: the chroot suffix, where the rootfs that will be installed
|
|
|
|
on the device has been created (e.g. "rootfs_qemu-amd64")
|
2020-06-07 06:53:34 +00:00
|
|
|
:param step: next installation step
|
|
|
|
:param steps: total installation steps
|
2020-12-18 21:14:13 +00:00
|
|
|
:param boot_label: label of the boot partition (e.g. "pmOS_boot")
|
2020-11-18 18:37:11 +00:00
|
|
|
:param root_label: label of the root partition (e.g. "pmOS_root")
|
2020-06-07 07:05:30 +00:00
|
|
|
:param split: create separate images for boot and root partitions
|
2020-06-09 13:43:25 +00:00
|
|
|
:param sdcard: path to sdcard device (e.g. /dev/mmcblk0) or None
|
2020-06-06 17:05:11 +00:00
|
|
|
"""
|
2017-05-26 20:08:45 +00:00
|
|
|
# Partition and fill image/sdcard
|
2020-06-07 06:53:34 +00:00
|
|
|
logging.info(f"*** ({step}/{steps}) PREPARE INSTALL BLOCKDEVICE ***")
|
2017-05-26 20:08:45 +00:00
|
|
|
pmb.chroot.shutdown(args, True)
|
2020-06-07 06:44:43 +00:00
|
|
|
(size_boot, size_root) = get_subpartitions_size(args, suffix)
|
2018-01-28 23:25:21 +00:00
|
|
|
if not args.rsync:
|
2020-06-06 17:05:11 +00:00
|
|
|
pmb.install.blockdevice.create(args, size_boot, size_root,
|
2020-06-09 13:43:25 +00:00
|
|
|
size_reserve, split, sdcard)
|
2020-06-07 07:05:30 +00:00
|
|
|
if not split:
|
2020-06-06 17:05:11 +00:00
|
|
|
pmb.install.partition(args, size_boot, size_reserve)
|
2020-06-07 07:05:30 +00:00
|
|
|
if not split:
|
2020-06-06 17:05:11 +00:00
|
|
|
root_id = 3 if size_reserve else 2
|
2020-06-09 13:43:25 +00:00
|
|
|
pmb.install.partitions_mount(args, root_id, sdcard)
|
2018-01-28 23:25:21 +00:00
|
|
|
|
2020-12-18 21:14:13 +00:00
|
|
|
pmb.install.format(args, size_reserve, boot_label, root_label, sdcard)
|
2017-05-26 20:08:45 +00:00
|
|
|
|
|
|
|
# Just copy all the files
|
2020-06-07 06:53:34 +00:00
|
|
|
logging.info(f"*** ({step + 1}/{steps}) FILL INSTALL BLOCKDEVICE ***")
|
2020-06-07 06:44:43 +00:00
|
|
|
copy_files_from_chroot(args, suffix)
|
2018-02-01 22:44:20 +00:00
|
|
|
create_home_from_skel(args)
|
|
|
|
configure_apk(args)
|
2018-04-08 14:12:01 +00:00
|
|
|
copy_ssh_keys(args)
|
2021-03-12 15:52:15 +00:00
|
|
|
|
|
|
|
# Don't try to embed firmware on split images since there's no
|
|
|
|
# place to put it and it will end up in /dev of the chroot instead
|
|
|
|
if not split:
|
|
|
|
embed_firmware(args, suffix)
|
|
|
|
|
2021-01-08 15:17:21 +00:00
|
|
|
if sdcard:
|
|
|
|
logging.info("Unmounting SD card (this may take a while "
|
|
|
|
"to sync, please wait)")
|
2017-05-26 20:08:45 +00:00
|
|
|
pmb.chroot.shutdown(args, True)
|
|
|
|
|
2018-07-15 21:41:31 +00:00
|
|
|
# Convert rootfs to sparse using img2simg
|
2020-01-22 17:48:45 +00:00
|
|
|
sparse = args.sparse
|
|
|
|
if sparse is None:
|
|
|
|
sparse = args.deviceinfo["flash_sparse"] == "true"
|
|
|
|
|
2020-06-09 13:43:25 +00:00
|
|
|
if sparse and not split and not sdcard:
|
2018-07-15 21:41:31 +00:00
|
|
|
logging.info("(native) make sparse rootfs")
|
2019-10-05 12:48:11 +00:00
|
|
|
pmb.chroot.apk.install(args, ["android-tools"])
|
2017-08-02 16:21:50 +00:00
|
|
|
sys_image = args.device + ".img"
|
|
|
|
sys_image_sparse = args.device + "-sparse.img"
|
|
|
|
pmb.chroot.user(args, ["img2simg", sys_image, sys_image_sparse],
|
2017-10-12 20:08:10 +00:00
|
|
|
working_dir="/home/pmos/rootfs/")
|
2017-08-02 16:21:50 +00:00
|
|
|
pmb.chroot.user(args, ["mv", "-f", sys_image_sparse, sys_image],
|
2017-10-12 20:08:10 +00:00
|
|
|
working_dir="/home/pmos/rootfs/")
|
2017-08-02 16:21:50 +00:00
|
|
|
|
2020-06-07 06:08:06 +00:00
|
|
|
|
2020-11-18 18:53:54 +00:00
|
|
|
def print_flash_info(args):
|
2020-06-07 06:08:06 +00:00
|
|
|
""" Print flashing information, based on the deviceinfo data and the
|
2020-11-18 18:53:54 +00:00
|
|
|
pmbootstrap arguments. """
|
2021-02-13 11:51:28 +00:00
|
|
|
logging.info("") # make the note stand out
|
2020-11-18 18:53:54 +00:00
|
|
|
logging.info("*** FLASHING INFORMATION ***")
|
2017-07-21 18:26:56 +00:00
|
|
|
|
|
|
|
# System flash information
|
2020-02-04 10:30:28 +00:00
|
|
|
method = args.deviceinfo["flash_method"]
|
|
|
|
flasher = pmb.config.flashers.get(method, {})
|
|
|
|
flasher_actions = flasher.get("actions", {})
|
|
|
|
requires_split = flasher.get("split", False)
|
|
|
|
|
2020-11-18 18:57:21 +00:00
|
|
|
if method == "none":
|
|
|
|
logging.info("Refer to the installation instructions of your device,"
|
|
|
|
" or the generic install instructions in the wiki.")
|
|
|
|
logging.info("https://wiki.postmarketos.org/wiki/Installation_guide"
|
|
|
|
"#pmbootstrap_flash")
|
|
|
|
return
|
|
|
|
|
|
|
|
logging.info("Run the following to flash your installation to the"
|
|
|
|
" target device:")
|
|
|
|
|
2020-02-04 10:30:28 +00:00
|
|
|
if "flash_rootfs" in flasher_actions and not args.sdcard and \
|
|
|
|
bool(args.split) == requires_split:
|
2018-03-30 01:11:20 +00:00
|
|
|
logging.info("* pmbootstrap flasher flash_rootfs")
|
|
|
|
logging.info(" Flashes the generated rootfs image to your device:")
|
2020-02-04 10:30:28 +00:00
|
|
|
if args.split:
|
2020-06-07 06:17:07 +00:00
|
|
|
logging.info(f" {args.work}/chroot_native/home/pmos/rootfs/"
|
|
|
|
f"{args.device}-rootfs.img")
|
2020-02-04 10:30:28 +00:00
|
|
|
else:
|
2020-06-07 06:17:07 +00:00
|
|
|
logging.info(f" {args.work}/chroot_native/home/pmos/rootfs/"
|
|
|
|
f"{args.device}.img")
|
|
|
|
logging.info(" (NOTE: This file has a partition table, which"
|
|
|
|
" contains /boot and / subpartitions. That way we"
|
|
|
|
" don't need to change the partition layout on your"
|
|
|
|
" device.)")
|
|
|
|
|
|
|
|
# if current flasher supports vbmeta and partition is explicitly specified
|
|
|
|
# in deviceinfo
|
2020-05-13 19:32:49 +00:00
|
|
|
if "flash_vbmeta" in flasher_actions and \
|
|
|
|
(args.deviceinfo["flash_fastboot_partition_vbmeta"] or
|
|
|
|
args.deviceinfo["flash_heimdall_partition_vbmeta"]):
|
2020-03-19 14:11:52 +00:00
|
|
|
logging.info("* pmbootstrap flasher flash_vbmeta")
|
|
|
|
logging.info(" Flashes vbmeta image with verification disabled flag.")
|
|
|
|
|
2020-02-04 10:30:28 +00:00
|
|
|
# Most flash methods operate independently of the boot partition.
|
|
|
|
# (e.g. an Android boot image is generated). In that case, "flash_kernel"
|
|
|
|
# works even when partitions are split or installing for sdcard.
|
|
|
|
# This is not possible if the flash method requires split partitions.
|
2020-06-07 06:17:07 +00:00
|
|
|
if "flash_kernel" in flasher_actions and \
|
|
|
|
(not requires_split or args.split):
|
2020-02-04 10:30:28 +00:00
|
|
|
logging.info("* pmbootstrap flasher flash_kernel")
|
|
|
|
logging.info(" Flashes the kernel + initramfs to your device:")
|
|
|
|
if requires_split:
|
2020-06-07 06:17:07 +00:00
|
|
|
logging.info(f" {args.work}/chroot_native/home/pmos/rootfs/"
|
|
|
|
f"{args.device}-boot.img")
|
2020-02-04 10:30:28 +00:00
|
|
|
else:
|
2020-06-07 06:17:07 +00:00
|
|
|
logging.info(f" {args.work}/chroot_rootfs_{args.device}/boot")
|
2020-02-04 10:30:28 +00:00
|
|
|
|
|
|
|
if "boot" in flasher_actions:
|
2018-03-30 00:52:38 +00:00
|
|
|
logging.info(" (NOTE: " + method + " also supports booting"
|
|
|
|
" the kernel/initramfs directly without flashing."
|
|
|
|
" Use 'pmbootstrap flasher boot' to do that.)")
|
|
|
|
|
2017-07-21 18:26:56 +00:00
|
|
|
# Export information
|
2020-02-04 10:30:28 +00:00
|
|
|
logging.info("* If the above steps do not work, you can also create"
|
|
|
|
" symlinks to the generated files with 'pmbootstrap export'"
|
|
|
|
" and flash outside of pmbootstrap.")
|
2017-08-24 21:07:36 +00:00
|
|
|
|
|
|
|
|
2020-11-18 18:53:54 +00:00
|
|
|
def install_recovery_zip(args, steps):
|
|
|
|
logging.info(f"*** ({steps}/{steps}) CREATING RECOVERY-FLASHABLE ZIP ***")
|
2017-08-24 21:07:36 +00:00
|
|
|
suffix = "buildroot_" + args.deviceinfo["arch"]
|
2020-06-07 06:44:43 +00:00
|
|
|
mount_device_rootfs(args, f"rootfs_{args.device}", suffix)
|
2017-08-24 21:07:36 +00:00
|
|
|
pmb.install.recovery.create_zip(args, suffix)
|
|
|
|
|
|
|
|
# Flash information
|
2020-11-18 18:53:54 +00:00
|
|
|
logging.info("*** FLASHING INFORMATION ***")
|
2018-10-24 06:53:55 +00:00
|
|
|
logging.info("Flashing with the recovery zip is explained here:")
|
2020-11-18 18:57:21 +00:00
|
|
|
logging.info("https://postmarketos.org/recoveryzip")
|
2017-08-24 21:07:36 +00:00
|
|
|
|
|
|
|
|
2020-06-06 21:38:34 +00:00
|
|
|
def install_on_device_installer(args, step, steps):
|
|
|
|
# Generate the rootfs image
|
2020-10-06 09:34:19 +00:00
|
|
|
if not args.ondev_no_rootfs:
|
|
|
|
suffix_rootfs = f"rootfs_{args.device}"
|
|
|
|
install_system_image(args, 0, suffix_rootfs, step=step, steps=steps,
|
|
|
|
split=True)
|
|
|
|
step += 2
|
2020-06-06 21:38:34 +00:00
|
|
|
|
|
|
|
# Prepare the installer chroot
|
|
|
|
logging.info(f"*** ({step}/{steps}) CREATE ON-DEVICE INSTALLER ROOTFS ***")
|
|
|
|
step += 1
|
|
|
|
packages = ([f"device-{args.device}",
|
|
|
|
"postmarketos-ondev"] +
|
|
|
|
get_kernel_package(args, args.device) +
|
|
|
|
get_nonfree_packages(args, args.device))
|
|
|
|
suffix_installer = f"installer_{args.device}"
|
|
|
|
pmb.chroot.apk.install(args, packages, suffix_installer)
|
|
|
|
|
|
|
|
# Move rootfs image into installer chroot
|
|
|
|
img_path_dest = f"{args.work}/chroot_{suffix_installer}/var/lib/rootfs.img"
|
2020-10-06 09:34:19 +00:00
|
|
|
if not args.ondev_no_rootfs:
|
|
|
|
img = f"{args.device}-root.img"
|
|
|
|
img_path_src = f"{args.work}/chroot_native/home/pmos/rootfs/{img}"
|
|
|
|
logging.info(f"({suffix_installer}) add {img} as /var/lib/rootfs.img")
|
|
|
|
pmb.install.losetup.umount(args, img_path_src)
|
|
|
|
pmb.helpers.run.root(args, ["mv", img_path_src, img_path_dest])
|
2020-06-06 21:38:34 +00:00
|
|
|
|
|
|
|
# Run ondev-prepare, so it may generate nice configs from the channel
|
|
|
|
# properties (e.g. to display the version number), or transform the image
|
|
|
|
# file into another format. This can all be done without pmbootstrap
|
|
|
|
# changes in the postmarketos-ondev package.
|
2020-06-29 18:18:35 +00:00
|
|
|
logging.info(f"({suffix_installer}) ondev-prepare")
|
2020-06-06 21:38:34 +00:00
|
|
|
channel = pmb.config.pmaports.read_config(args)["channel"]
|
|
|
|
channel_cfg = pmb.config.pmaports.read_config_channel(args)
|
2020-06-29 18:13:01 +00:00
|
|
|
env = {"ONDEV_CHANNEL": channel,
|
|
|
|
"ONDEV_CHANNEL_BRANCH_APORTS": channel_cfg["branch_aports"],
|
|
|
|
"ONDEV_CHANNEL_BRANCH_PMAPORTS": channel_cfg["branch_pmaports"],
|
|
|
|
"ONDEV_CHANNEL_DESCRIPTION": channel_cfg["description"],
|
2020-06-29 18:17:29 +00:00
|
|
|
"ONDEV_CHANNEL_MIRRORDIR_ALPINE": channel_cfg["mirrordir_alpine"],
|
2020-07-09 21:35:31 +00:00
|
|
|
"ONDEV_CIPHER": args.cipher,
|
2020-06-29 18:17:29 +00:00
|
|
|
"ONDEV_PMBOOTSTRAP_VERSION": pmb.config.version,
|
|
|
|
"ONDEV_UI": args.ui}
|
2020-06-29 18:13:01 +00:00
|
|
|
pmb.chroot.root(args, ["ondev-prepare"], suffix_installer, env=env)
|
2020-06-06 21:38:34 +00:00
|
|
|
|
2020-11-17 14:24:20 +00:00
|
|
|
# Copy files specified with 'pmbootstrap install --ondev --cp'
|
|
|
|
if args.ondev_cp:
|
|
|
|
for host_src, chroot_dest in args.ondev_cp:
|
|
|
|
host_dest = f"{args.work}/chroot_{suffix_installer}/{chroot_dest}"
|
|
|
|
logging.info(f"({suffix_installer}) add {host_src} as"
|
|
|
|
f" {chroot_dest}")
|
|
|
|
pmb.helpers.run.root(args, ["install", "-Dm644", host_src,
|
|
|
|
host_dest])
|
|
|
|
|
2020-06-06 21:38:34 +00:00
|
|
|
# Remove $DEVICE-boot.img (we will generate a new one if --split was
|
|
|
|
# specified, otherwise the separate boot image is not needed)
|
2020-10-06 09:34:19 +00:00
|
|
|
if not args.ondev_no_rootfs:
|
|
|
|
img_boot = f"{args.device}-boot.img"
|
|
|
|
logging.info(f"(native) rm {img_boot}")
|
|
|
|
pmb.chroot.root(args, ["rm", f"/home/pmos/rootfs/{img_boot}"])
|
2020-06-06 21:38:34 +00:00
|
|
|
|
2021-02-08 21:46:37 +00:00
|
|
|
# Disable root login
|
|
|
|
setup_login(args, suffix_installer)
|
|
|
|
|
2020-06-06 21:38:34 +00:00
|
|
|
# Generate installer image
|
|
|
|
size_reserve = round(os.path.getsize(img_path_dest) / 1024 / 1024) + 200
|
2020-12-18 21:18:42 +00:00
|
|
|
boot_label = "pmOS_inst_boot"
|
|
|
|
if pmb.parse.version.compare(get_ondev_pkgver(args), "0.4.0") == -1:
|
|
|
|
boot_label = "pmOS_boot"
|
2020-11-18 18:37:11 +00:00
|
|
|
install_system_image(args, size_reserve, suffix_installer, step, steps,
|
2020-12-18 21:18:42 +00:00
|
|
|
boot_label, "pmOS_install", args.split, args.sdcard)
|
2020-06-06 21:38:34 +00:00
|
|
|
|
|
|
|
|
2021-06-03 22:36:37 +00:00
|
|
|
def cleanup(args, suffix):
|
|
|
|
pmb.chroot.root(args, ["rm", "/in-pmbootstrap"], suffix)
|
|
|
|
|
|
|
|
|
2020-10-06 10:13:13 +00:00
|
|
|
def create_device_rootfs(args, step, steps):
|
|
|
|
# List all packages to be installed (including the ones specified by --add)
|
|
|
|
# and upgrade the installed packages/apkindexes
|
|
|
|
logging.info(f'*** ({step}/{steps}) CREATE DEVICE ROOTFS ("{args.device}")'
|
|
|
|
' ***')
|
2020-10-07 17:24:22 +00:00
|
|
|
|
2020-12-09 20:37:28 +00:00
|
|
|
suffix = f"rootfs_{args.device}"
|
2020-10-07 17:24:22 +00:00
|
|
|
# Create user before installing packages, so post-install scripts of
|
|
|
|
# pmaports can figure out the username (legacy reasons: pmaports#820)
|
|
|
|
set_user(args)
|
|
|
|
|
2020-10-07 17:49:47 +00:00
|
|
|
# Fill install_packages
|
2017-08-24 21:07:36 +00:00
|
|
|
install_packages = (pmb.config.install_device_packages +
|
2018-02-24 21:49:10 +00:00
|
|
|
["device-" + args.device] +
|
pmbootstrap init: kernel selection / remove linux-pmos-lts (#1363)
* As discussed in IRC/matrix, we're removing `linux-postmarketos-lts`
for now. The kernel isn't used right now, and we save lots of
maintenance effort with not updating it every week or so.
* new config option `"kernel"` with possible values:
`"downstream", "mainline", "stable"` (downstream is always
`linux-$devicename`)
* ask for the kernel during `pmbootstrap init` if the device package
has kernel subpackages and install it in `_install.py`
* postmarketos-mkinitfs: display note instead of exit with error when
the `deviceinfo_dtb` file is missing (because we expect it to be
missing for downstream kernels)
* device-sony-amami:
* add kernel subpackages for downstream, mainline
* set `deviceinfo_dtb`
* device-qemu-amd64: add kernel subpackages for stable, lts, mainline
* test cases and test data for new functions
* test case that checks all aports for right usage of the feature:
* don't mix specifying kernels in depends *and* subpackages
* 1 kernel in depends is maximum
* kernel subpackages must have a valid name
* Test if devices packages reference at least one kernel
* Remove `_build_device_depends_note()` which informs the user that
`--ignore-depends` can be used with device packages to avoid building
the kernel. The idea was to make the transition easier after a change
we did months ago, and now the kernel doesn't always get built before
building the device package so it's not relevant anymore.
* pmb/chroot/other.py:
* Add autoinstall=True to kernel_flavors_installed(). When the flag
is set, the function makes sure that at least one kernel for the
device is installed.
* Remove kernel_flavor_autodetect() function, wherever it was used,
it has been replaced with kernel_flavors_installed()[0].
* pmb.helpers.frontend.py: remove code to install at least one kernel,
kernel_flavors_installed() takes care of that now.
2018-04-03 23:50:09 +00:00
|
|
|
get_kernel_package(args, args.device) +
|
2020-07-20 06:57:01 +00:00
|
|
|
get_nonfree_packages(args, args.device) +
|
2021-01-24 09:00:22 +00:00
|
|
|
pmb.install.ui.get_recommends(args))
|
2019-12-10 16:31:38 +00:00
|
|
|
if not args.install_base:
|
2021-02-28 19:01:31 +00:00
|
|
|
install_packages = [p for p in install_packages
|
|
|
|
if p != "postmarketos-base"]
|
2017-08-24 21:07:36 +00:00
|
|
|
if args.ui.lower() != "none":
|
|
|
|
install_packages += ["postmarketos-ui-" + args.ui]
|
2020-04-05 02:27:13 +00:00
|
|
|
if args.ui_extras:
|
|
|
|
install_packages += ["postmarketos-ui-" + args.ui + "-extras"]
|
2020-10-07 17:49:47 +00:00
|
|
|
if args.extra_packages.lower() != "none":
|
|
|
|
install_packages += args.extra_packages.split(",")
|
|
|
|
if args.add:
|
|
|
|
install_packages += args.add.split(",")
|
2020-12-09 20:37:28 +00:00
|
|
|
locale_is_set = (args.locale != pmb.config.defaults["locale"])
|
|
|
|
if locale_is_set:
|
|
|
|
install_packages += ["lang", "musl-locales"]
|
2020-10-07 17:04:21 +00:00
|
|
|
|
|
|
|
pmb.helpers.repo.update(args, args.deviceinfo["arch"])
|
2017-08-24 21:07:36 +00:00
|
|
|
|
|
|
|
# Explicitly call build on the install packages, to re-build them or any
|
|
|
|
# dependency, in case the version increased
|
2020-06-22 10:51:07 +00:00
|
|
|
if args.build_pkgs_on_install:
|
|
|
|
for pkgname in install_packages:
|
|
|
|
pmb.build.package(args, pkgname, args.deviceinfo["arch"])
|
2017-08-24 21:07:36 +00:00
|
|
|
|
|
|
|
# Install all packages to device rootfs chroot (and rebuild the initramfs,
|
|
|
|
# because that doesn't always happen automatically yet, e.g. when the user
|
|
|
|
# installed a hook without pmbootstrap - see #69 for more info)
|
|
|
|
pmb.chroot.apk.install(args, install_packages, suffix)
|
|
|
|
for flavor in pmb.chroot.other.kernel_flavors_installed(args, suffix):
|
|
|
|
pmb.chroot.initfs.build(args, flavor, suffix)
|
|
|
|
|
|
|
|
# Set the user password
|
2021-02-08 21:46:37 +00:00
|
|
|
setup_login(args, suffix)
|
2017-08-24 21:07:36 +00:00
|
|
|
|
|
|
|
# Set the keymap if the device requires it
|
|
|
|
setup_keymap(args)
|
|
|
|
|
2017-10-13 19:18:24 +00:00
|
|
|
# Set timezone
|
|
|
|
pmb.chroot.root(args, ["setup-timezone", "-z", args.timezone], suffix)
|
|
|
|
|
2020-12-09 20:37:28 +00:00
|
|
|
# Set locale
|
|
|
|
if locale_is_set:
|
|
|
|
pmb.chroot.root(args, ["sed", "-i",
|
|
|
|
f"s/LANG=C.UTF-8/LANG={args.locale}/",
|
|
|
|
"/etc/profile.d/locale.sh"], suffix)
|
|
|
|
|
2018-03-17 18:41:41 +00:00
|
|
|
# Set the hostname as the device name
|
|
|
|
setup_hostname(args)
|
|
|
|
|
2021-02-13 11:00:43 +00:00
|
|
|
disable_sshd(args)
|
2021-06-03 22:36:37 +00:00
|
|
|
cleanup(args, suffix)
|
2021-02-13 11:00:43 +00:00
|
|
|
|
2020-10-06 10:13:13 +00:00
|
|
|
|
|
|
|
def install(args):
|
|
|
|
# Sanity checks
|
|
|
|
if not args.android_recovery_zip and args.sdcard:
|
|
|
|
sanity_check_sdcard(args)
|
|
|
|
sanity_check_sdcard_size(args)
|
|
|
|
if args.on_device_installer:
|
|
|
|
sanity_check_ondev_version(args)
|
|
|
|
|
|
|
|
# Number of steps for the different installation methods.
|
|
|
|
if args.no_image:
|
|
|
|
steps = 2
|
|
|
|
elif args.android_recovery_zip:
|
|
|
|
steps = 3
|
|
|
|
elif args.on_device_installer:
|
2020-10-06 09:34:19 +00:00
|
|
|
steps = 4 if args.ondev_no_rootfs else 7
|
2020-10-06 10:13:13 +00:00
|
|
|
else:
|
|
|
|
steps = 4
|
|
|
|
|
|
|
|
# Install required programs in native chroot
|
2020-10-06 10:26:01 +00:00
|
|
|
step = 1
|
|
|
|
logging.info(f"*** ({step}/{steps}) PREPARE NATIVE CHROOT ***")
|
2020-10-06 10:13:13 +00:00
|
|
|
pmb.chroot.apk.install(args, pmb.config.install_native_packages,
|
|
|
|
build=False)
|
2020-10-06 10:26:01 +00:00
|
|
|
step += 1
|
2020-10-06 10:13:13 +00:00
|
|
|
|
2020-10-06 09:34:19 +00:00
|
|
|
if not args.ondev_no_rootfs:
|
|
|
|
create_device_rootfs(args, step, steps)
|
|
|
|
step += 1
|
2020-10-06 10:13:13 +00:00
|
|
|
|
2020-06-07 06:08:06 +00:00
|
|
|
if args.no_image:
|
|
|
|
return
|
|
|
|
elif args.android_recovery_zip:
|
2020-11-18 18:53:54 +00:00
|
|
|
return install_recovery_zip(args, steps)
|
2020-06-07 06:08:06 +00:00
|
|
|
|
2020-06-06 21:38:34 +00:00
|
|
|
if args.on_device_installer:
|
|
|
|
# Runs install_system_image twice
|
2020-10-06 10:26:01 +00:00
|
|
|
install_on_device_installer(args, step, steps)
|
2020-06-06 21:38:34 +00:00
|
|
|
else:
|
2020-10-06 10:26:01 +00:00
|
|
|
install_system_image(args, 0, f"rootfs_{args.device}", step, steps,
|
2020-06-06 21:38:34 +00:00
|
|
|
split=args.split, sdcard=args.sdcard)
|
2021-02-13 11:51:28 +00:00
|
|
|
|
2020-11-18 18:53:54 +00:00
|
|
|
print_flash_info(args)
|
2021-02-13 11:00:43 +00:00
|
|
|
print_sshd_info(args)
|
2021-02-13 11:51:28 +00:00
|
|
|
|
|
|
|
# Leave space before 'chroot still active' note
|
|
|
|
logging.info("")
|