initial commit

This commit is contained in:
Sebastian Hugentobler 2021-02-08 15:50:20 +01:00
commit 1b63fd18b7
Signed by: shu
GPG Key ID: BB32CF3CA052C2F0
5 changed files with 580 additions and 0 deletions

6
.gitignore vendored Executable file
View File

@ -0,0 +1,6 @@
*~
.DS_Store
*.swp
*.lock*
.void-mklive
void-pbp.img.xz

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) Sebastian Hugentobler <sebastian@vanwa.ch>
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.

79
README.md Normal file
View File

@ -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.

367
bootstrap Executable file
View File

@ -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 <<EOF
tmpfs /tmp tmpfs defaults,nosuid,nodev 0 0
$boot_uuid /boot vfat defaults 0 0
/dev/void/root / xfs defaults 0 0
/dev/void/swap swap swap defaults 0 0
EOF
}
set_boot_scr() {
local install_dev
install_dev="$(get_value "install_dev" "installation device")"
local boot_txt="/mnt/boot/boot.txt"
local boot_scr="/mnt/boot/boot.scr"
local boot_txt_mine="/mnt/boot/boot.txt.mine"
local root_uuid="$(blkid | grep ${install_dev}p2 | awk '{print $2}' | sed 's/"//g')"
sed -i "s|root=PARTUUID=|root=/dev/void/root rd.auto=1 cryptdevice=${root_uuid}:lvm|g" "$boot_txt"
cp "$boot_txt" "$boot_txt_mine"
mkimage -A arm -O linux -T script -C none -n "boot script" -d "$boot_txt" "$boot_scr"
}
set_sudoers() {
sed -i 's/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/g' /mnt/etc/sudoers
}
set_user() {
local user_name
user_name="$(get_value "user_name" "username")"
local user_pw
user_pw="$(get_value "user_pw" "user password")"
chroot /mnt /bin/env -i \
user_name="$user_name" \
user_pw="$user_pw" \
/bin/bash <<"EOT"
useradd --groups wheel --create-home --shell /bin/bash --user-group $user_name
echo "$user_name:$user_pw" | chpasswd
EOT
}
set_base_conf() {
local timezone
timezone="$(get_value "timezone" "timezone")"
local keymap
keymap="$(get_value "keymap" "keymap")"
local hostname
hostname="$(get_value "hostname" "hostname")"
local locale
locale="$(get_value "locale" "locale")"
echo "$locale" >> /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 <<EOF
#
# /etc/hosts: static lookup table for host names
#
#<ip-address> <hostname.domain.org> <hostname>
127.0.0.1 localhost.localdomain localhost $hostname
::1 localhost.localdomain localhost ip6-localhost $hostname
# End of file
EOF
cat >/mnt/etc/rc.conf <<EOF
# /etc/rc.conf - system configuration for void
# Set the host name.
#
# NOTE: it's preferred to declare the hostname in /etc/hostname instead:
# - echo myhost > /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

107
mk_pbp_img Executable file
View File

@ -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