commit 1b63fd18b7626096617879e5505a91fe35c8b871 Author: Sebastian Hugentobler Date: Mon Feb 8 15:50:20 2021 +0100 initial commit diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..d5b0ae1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*~ +.DS_Store +*.swp +*.lock* +.void-mklive +void-pbp.img.xz diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b157657 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Sebastian Hugentobler + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..86181ba --- /dev/null +++ b/README.md @@ -0,0 +1,79 @@ +# Install Scripts for Void Linux on Pinebook Pro +Before using either of the scripts in this repository, read through them to +clearly understand what they do. They are very opinionated and specifically +written to cater to my own needs (for example the use of `sudo`, other people +might have different setups). It is, however, easy to change things around. + +By default, the `bootstrap` script creates a minimal installation on the emmc storage, +with full disk encryption via lvm on luks. Two volumes `swap` and `root` are created, +the latter is formatted with an xfs filesystem. Additionally one user is created +(with access to sudo via the wheel group) and keymap, hostname and timezone get set. + +This gets you to a booting system, going on from there is out of scope here +as there are many ways to do that (for myself, I use `stow` to set up everything). + +An important thing to keep in mind is that not all commands in the `bootstrap` +script are idempotent, that makes it all the more important to understand what they +do and to be sure to backup all important data. + +# Scripts +## mk_pbp_img +Create a live image to boot void linux on the pinebook pro. Needs to be run on an +existing void linux system (docker might be possible with a working buildx and some adaptions with the mounting of filesystems). + +A copy of the [void-mklive](https://github.com/void-linux/void-mklive.git) +repository is downloaded next to the script into `.void-mklive` and used for +building the image. + +The script assumes it is running on an `x86_64` architecture, if that is not the case, +it needs to be changed (this applies to the use of `qemu-aarch64-static` to get a chroot). + +The following tools need to be accessible in `PATH`: + +- git +- make +- qemu-aarch64-static +- sudo +- xz + +If there is an argument provided to the script, it is treated as the folder to where +the compressed image is written, if no argument is given, the current working +directory is used. + +After a successful build, the finished image can be found in the directory described +above with a filename of `void-pbp.img.xz` + +Write it to a microSD card as such: +- `xz -d < void-pbp.img.xz | sudo dd of=/dev/mmcblk0 bs=4M status=progress` +- `sudo sync` + +Be ***very*** careful to get the parameter for `of` right, otherwise you can destroy your system. + +MicroSD cards can be fickle, it sometimes is helpful to not take them out immediately, even after running `sync`. +If booting from the card hangs, write the image again onto it or use a different card. + +## bootstrap +Install void linux to the internal mmc storage of the pinebook pro or use it for some +maintenance task. + +Run it in either of two ways: + +### non-interactive +`bootstrap full` + +Run a full installation, this will overwrite all data on the storage. + +Runs the `full_install` command internally. + +### interactive +`bootstrap` + +Run `help` to get a list of commands you can run and quit interactive mode +with typing `exit`. + +A useful thing to do here is the `repair` command. Sets up all the needed filesystems +and opens a chroot. + +Again, it is highly recommended to read what the respective commands do and to adapt +them to your own needs. + diff --git a/bootstrap b/bootstrap new file mode 100755 index 0000000..b4f686e --- /dev/null +++ b/bootstrap @@ -0,0 +1,367 @@ +#!/usr/bin/env bash + +set -o errexit +set -o pipefail + +CONFIG="$(mktemp)" +declare -rgA default_values=( + ["wifi_if"]="wlan0" + ["install_dev"]="/dev/mmcblk2" + ["repo"]="https://alpha.de.repo.voidlinux.org/current/aarch64" + ["arch"]="aarch64" + ["timezone"]="Europe/Zurich" + ["keymap"]="uk" + ["locale"]="en_US.UTF-8 UTF-8" +) + +get_value() { + local white=$'\e[97m' + local nocolour=$'\e[0m' + + local var_name="$1" + local prompt="$2" + local secure="" + + if [ -n "$3" ]; then + secure="s" + fi + + . "$CONFIG" + if [ -z "${!var_name}" ]; then + local def_val="${default_values[$var_name]}" + read -${secure}rp "$white$prompt [$def_val]:$nocolour " value + + echo "export $var_name=\"${value:-$def_val}\"" >> "$CONFIG" + . "$CONFIG" + fi + + echo "${!var_name}" + +} + +network() { + local wifi_if + wifi_if="$(get_value "wifi_if" "wifi interface name")" + + ip link set "$wifi_if" up + + local wifi_ssid + wifi_ssid="$(get_value "wifi_ssid" "wifi ssid")" + local wifi_pw + wifi_pw="$(get_value "wifi_pw" "wifi password" 1)" + + wpa_supplicant -B -i "$wifi_if" -c <(wpa_passphrase "$wifi_ssid" "$wifi_pw") + sv restart dhcpcd +} + +datetime() { + local datetime + datetime="$(get_value "datetime" "date and time now (like 2020-01-01 12:00)")" + + date "+%Y--%m-%d %T" --set="$datetime" + hwclock --systohc +} + +partition() { + local install_dev + install_dev="$(get_value "install_dev" "installation device")" + + if [ ! -e "$install_dev" ]; then + echo "device node $install_dev does not exist" + exit 1 + fi + + sfdisk --force "$install_dev" << EOF +label: gpt + +start=16MiB size=512MiB, type=bc13c2ff-59e6-4262-a352-b275fd6f7172 +type=b921b045-1df0-41c3-af44-4c6f280d3fae +EOF + + mkfs.vfat -F32 "$install_dev"p1 + +} + +create_luks() { + local install_dev + install_dev="$(get_value "install_dev" "installation device")" + + cryptsetup luksFormat "$install_dev"p2 +} + +open_luks() { + local install_dev + install_dev="$(get_value "install_dev" "installation device")" + + cryptsetup open "$install_dev"p2 void +} + +create_lvm() { + pvcreate /dev/mapper/void + vgcreate void /dev/mapper/void + + lvcreate -L 4G void -n swap + lvcreate -l 100%FREE void -n root +} + +open_lvm() { + vgchange --activate y +} + +make_filesystems() { + mkswap -L SWAP /dev/void/swap + mkfs.xfs -f -L ROOT /dev/void/root +} + +mount_filesystems() { + local install_dev + install_dev="$(get_value "install_dev" "installation device")" + + mount /dev/void/root /mnt + mkdir -p /mnt/boot + mount "$install_dev"p1 /mnt/boot + + swapon /dev/void/swap +} + +install_basesystem() { + local repo + repo="$(get_value "repo" "package repository")" + local arch + arch="$(get_value "arch" "installation architecture")" + + XBPS_ARCH=$arch xbps-install -S -y -r /mnt -R "$repo" base-system pinebookpro-base dracut lvm2 cryptsetup sudo stow << 'EOF' +y +EOF + cp /etc/resolv.conf /mnt/etc/ +} + +mount_special_filesystems() { + mount --rbind /sys /mnt/sys && mount --make-rslave /mnt/sys + mount --rbind /dev /mnt/dev && mount --make-rslave /mnt/dev + mount --rbind /proc /mnt/proc && mount --make-rslave /mnt/proc + mount --rbind /tmp /mnt/tmp && mount --make-rslave /mnt/tmp +} + +set_fstab() { + local install_dev + install_dev="$(get_value "install_dev" "installation device")" + + local boot_uuid="$(blkid | grep ${install_dev}p1 | awk '{print $2}')" + cat >/mnt/etc/fstab <> /etc/default/libc-locales + + chroot /mnt /bin/env -i \ + timezone="$timezone" \ + /bin/bash <<"EOT" +xbps-reconfigure -f glibc-locales +ln -sf /usr/share/zoneinfo/$timezone /etc/localtime +EOT + + echo "$hostname" > /mnt/etc/hostname + + cat >/mnt/etc/hosts < +127.0.0.1 localhost.localdomain localhost $hostname +::1 localhost.localdomain localhost ip6-localhost $hostname + +# End of file +EOF + + cat >/mnt/etc/rc.conf < /etc/hostname +# +#HOSTNAME="void-live" + +# Set RTC to UTC or localtime. +#HARDWARECLOCK="UTC" + +# Set timezone, availables timezones at /usr/share/zoneinfo. +TIMEZONE="$timezone" + +# Keymap to load, see loadkeys(8). +KEYMAP="$keymap" + +# Console font to load, see setfont(8). +#FONT="lat9w-16" + +# Console map to load, see setfont(8). +#FONT_MAP= + +# Font unimap to load, see setfont(8). +#FONT_UNIMAP= + +# Amount of ttys which should be setup. +#TTYS= +EOF +} + +tidy_up() { + umount -R /mnt +} + +full_install() { + datetime + network + partition + create_luks + open_luks + create_lvm + open_lvm + make_filesystems + mount_filesystems + install_basesystem + mount_special_filesystems + set_fstab + set_boot_scr + set_sudoers + set_user + set_base_conf + tidy_up +} + +repair() { + open_luks + open_lvm + mount_filesystems + mount_special_filesystems + + chroot /mnt bash + tidy_up +} + +help() { + cat << EOF +the following commands are available: + + datetime + network + partition + create_luks + open_luks + create_lvm + open_lvm + make_filesystems + mount_filesystems + install_basesystem + mount_special_filesystems + set_fstab + set_boot_scr + set_sudoers + set_user + set_base_conf + full_install + repair + tidy_up + help + +ensure to understand what they are doing before using them +EOF +} + +commands=( + "datetime" + "network" + "partition" + "create_luks" + "open_luks" + "open_lvm" + "make_filesystems" + "mount_filesystems" + "set_fstab" + "set_boot_scr" + "set_sudoers" + "set_user" + "set_base_conf" + "full_install" + "repair" + "tidy_up" + "help" +) + +cmd_loop() { + local cmd + + while [[ "$cmd" != "exit" ]]; do + read -rp "${white}>$nocolour " cmd + + if [[ " ${commands[@]} " =~ " ${cmd} " ]]; then + $cmd + else + if [ "$cmd" != "exit" ]; then + echo "no such command" + fi + fi + done +} + +if [ "$1" == "full" ]; then + full_install +else + cmd_loop +fi diff --git a/mk_pbp_img b/mk_pbp_img new file mode 100755 index 0000000..9896d68 --- /dev/null +++ b/mk_pbp_img @@ -0,0 +1,107 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +ROOT_DIR="$(dirname "$(readlink -f "$0")")" +OUT_DIR="${1:-$(pwd)}" + +TMP_DIR="$(mktemp --directory)" +TMP_DIR_PFS="$(mktemp --directory)" +TMP_DIR_MOUNT="$(mktemp --directory)" + +TOOLS=(git make sudo qemu-aarch64-static xz) + +GIT_REPO=https://github.com/void-linux/void-mklive.git +GIT_REV=f71eb4bb81004b50884011ef5e0d00f99bc2892a +GIT_DIR="$ROOT_DIR/.void-mklive" + +cleanup() { + cleanup_mounts + sudo rm -r "$TMP_DIR" "$TMP_DIR_PFS" "$TMP_DIR_MOUNT" +} + +cleanup_mounts() { + sudo losetup -D + sudo umount --recursive "$TMP_DIR_MOUNT" || true +} + +check_tools() { + for tool in ${TOOLS[@]}; do + if ! command -v "$tool" &> /dev/null + then + echo "$tool could not be found" + exit 1 + fi + done +} + +init_void_mklive() { + if [ ! -d "$GIT_DIR" ]; then + git clone "$GIT_REPO" "$GIT_DIR" + cd "$GIT_DIR" && git checkout "$GIT_REV" + fi + + cd "$GIT_DIR" + + if [ "$(git rev-parse HEAD)" != "$GIT_REV" ]; then + git fetch + git checkout "$GIT_REV" + fi + + make + sed -i 's/ROOTFS_TARBALL#void-/ROOTFS_TARBALL#*void-/g' "$GIT_DIR/mkimage.sh" +} + +build_img() { + local rootfs_file="$TMP_DIR/rootfs.tar.xz" + local platformfs_file="$TMP_DIR/void-pinebookpro-PLATFORMFS.tar.xz" + local img="$TMP_DIR/void-pbp.img" + + cd "$GIT_DIR" + + sudo ./mkrootfs.sh -o "$rootfs_file" aarch64 + sudo ./mkplatformfs.sh -p "dracut lvm2 cryptsetup" -o "$platformfs_file" pinebookpro "$rootfs_file" + sudo ./mkimage.sh -B 256MiB -o "$img" "$platformfs_file" + + sudo xz --decompress --stdout "$img.xz" > "$img" + local loop_dev="$(sudo losetup --show -f -P "$img")" + + if [ ! -z "$DISCOVER_DEV" ]; then # needed if building inside a docker container + local partitions=$(lsblk --raw --output "MAJ:MIN" --noheadings ${loop_dev} | tail -n +2) + counter=1 + for i in $partitions; do + local maj=$(echo $i | cut -d: -f1) + local min=$(echo $i | cut -d: -f2) + if [ ! -e "${loop_dev}p${counter}" ]; then mknod ${loop_dev}p${counter} b $maj $min; fi + counter=$((counter + 1)) + done + fi + + sudo mount "$loop_dev"p2 "$TMP_DIR_MOUNT" + sudo mount "$loop_dev"p1 "$TMP_DIR_MOUNT"/boot + + sudo cp "$ROOT_DIR/bootstrap" "$TMP_DIR_MOUNT/usr/bin/bootstrap" + sudo chmod +x "$TMP_DIR_MOUNT/bin/bootstrap" + + sudo cp "$(which qemu-aarch64-static)" "$TMP_DIR_MOUNT/usr/bin/" + + sudo chroot "$TMP_DIR_MOUNT" qemu-aarch64-static /bin/bash <<"EOT" +ln -s /etc/sv/dhcpcd /etc/runit/runsvdir/default/ +EOT + + sudo rm "$TMP_DIR_MOUNT/usr/bin/qemu-aarch64-static" + cleanup_mounts + + mkdir -p "$OUT_DIR" + xz --threads=0 --compress --stdout "$img" > "$OUT_DIR/$(basename $img.xz)" + + echo "built pinebookpro image: $OUT_DIR/$(basename $img.xz)" +} + +trap cleanup 0 SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM + +check_tools +init_void_mklive +build_img