#!/bin/bash -x
+# Copyright (C) 2016 Ian Kelling
+
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
set -eE -o pipefail
-trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?"' ERR
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
# # fai's setup-storage won't do btrfs on luks,
# # so we do it ourself :)
#### begin configuration
-bootn=3
rootn=1
swapn=2
+bootn=3
bios_grubn=4
-boot_mib=1500
+boot_mib=4000
##### end configuration
-add-part() {
+add-part() { # add partition suffix to $dev
local d ret
if [[ $# == 1 ]]; then
d=$dev
lastn=$bios_grubn
-hds=()
+hdds=()
ssds=()
cd /sys/block
for disk in [sv]d[a-z]; do
case $(cat $disk/queue/rotational) in
0) ssds+=(/dev/$disk) ;;
- 1) hds+=(/dev/$disk) ;;
+ 1) hdds+=(/dev/$disk) ;;
*) echo "$0: error: unknown /sys/block/$disk/queue/rotational: \
$(cat $disk/queue/rotational)"; exit 1 ;;
esac
if (( ${#ssds[@]} > 0 )); then
short_devs=( ${ssds[@]} )
else
- short_devs=( ${hds[@]} )
+ short_devs=( ${hdds[@]} )
fi
# check if the partitions exist have the right filesystems
done
if [[ ! $DISTRO ]]; then
- if ifclass STABLE; then
+ if ifclass STABLE_BOOTSTRAP; then
+ DISTRO=debianstable_bootstrap
+ elif ifclass STRETCH64; then
+ DISTRO=debiantesting
+ elif ifclass STABLE; then
DISTRO=debianstable
+ elif ifclass XENIAL64; then
+ DISTRO=ubuntuxenial
+ elif ifclass BELENOS64; then
+ DISTRO=trisquelbelenos
else
- DISTRO=debiantesting
+ echo "PARTITIONER ERROR: no distro class/var set" >&2
+ exit 1
fi
fi
-
case ${#boot_devs[@]} in
# need double the space if we are raid 10, and then
# might as well give some extra overhead.
esac
}
-first_boot_dev=$(bootdev ${devs[0]})
+first_boot_dev=${boot_devs[0]}
# keyfiles generated like:
# head -c 2048 /dev/urandom | od | s dd of=/q/root/luks/host-demohost
luks_dir=${LUKS_DIR:-/var/lib/fai/config/distro-install-common/luks}
+
+if [[ ! -e $luks_dir/host-$HOSTNAME ]]; then
+ echo "$0: error: no key for hostname at $luks_dir/host-$HOSTNAME" >&2
+ exit 1
+fi
+
if ifclass tp; then
lukspw=$(cat $luks_dir/traci)
else
bios_grubn=4
# 1.5 x based on https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Installation_Guide/sect-disk-partitioning-setup-x86.html#sect-custom-partitioning-x86
swap_mib=$(( $(grep ^MemTotal: /proc/meminfo | \
- awk '{print $2}') * 3/(${#devs[@]} * 2 ) / 1024 ))
+ awk '{print $2}') * 3/(${#devs[@]} * 2 ) / 1024 ))
mkdir -p /tmp/fai
+root_devs=()
+for dev in ${devs[@]}; do
+ root_devs+=(`rootdev`)
+done
shopt -s nullglob
if $partition; then
for dev in ${devs[@]}; do
# parted print error output is expected. example:
# Error: /dev/vda: unrecognised disk label
disk_mib=$(( $(parted -m $dev unit MiB print | \
- sed -nr "s#^/dev/[^:]+:([0-9]+).*#\1#p") - 1))
+ sed -nr "s#^/dev/[^:]+:([0-9]+).*#\1#p") - 1))
root_end=$(( disk_mib - swap_mib - boot_mib / ${#boot_devs[@]} ))
swap_end=$(( root_end + swap_mib))
parted -s $dev mklabel gpt
- # gpt ubuntu cloud image uses ~4. fai uses 1 MiB.
- # I read something in the parted manual saying cheap flash media
- # likes to start at 4.
# MiB because parted complains about alignment otherwise.
pcmd="parted -a optimal -s -- $dev"
$pcmd mkpart primary "ext3" 4MiB ${root_end}MiB
$pcmd mkpart primary "linux-swap" ${root_end}MiB ${swap_end}MiB
$pcmd mkpart primary "" ${swap_end}MiB ${disk_mib}MiB
+ # gpt ubuntu cloud image uses ~4. fai uses 1 MiB.
+ # I read something in the parted manual saying cheap flash media
+ # likes to start at 4.
$pcmd mkpart primary "" 1MiB 4MiB
$pcmd set $bios_grubn bios_grub on
$pcmd set $bootn boot on # generally not needed on modern systems
cryptsetup luksOpen `rootdev` `root-cryptname` \
--key-file $luks_dir/host-$HOSTNAME
done
- ls -la /dev/btrfs-control
+ ls -la /dev/btrfs-control # this was probably for debugging...
sleep 1
bpart $(for dev in ${devs[@]}; do root-cryptdev; done)
bpart ${boot_devs[@]}
sleep 1
fi
-mount -o subvolid=0 $first_root_crypt /mnt
-# systemd creates subvolumes we want to delete.
-s=($(btrfs subvolume list --sort=-path /mnt |
- sed -rn "s#^.*path\s*(root_$DISTRO/\S+)\s*\$#\1#p"))
-for subvol in ${s[@]}; do btrfs subvolume delete /mnt/$subvol; done
-btrfs subvolume set-default 0 /mnt
-[[ ! -e /mnt/root_$DISTRO ]] || btrfs subvolume delete /mnt/root_$DISTRO
+if [[ $DISTRO != debianstable_bootstrap ]]; then
+ # bootstrap distro doesn't use separate encrypted root.
+ mount -o subvolid=0 $first_root_crypt /mnt
+ # systemd creates subvolumes we want to delete.
+ s=($(btrfs subvolume list --sort=-path /mnt |
+ sed -rn "s#^.*path\s*(root_$DISTRO/\S+)\s*\$#\1#p"))
+ for subvol in ${s[@]}; do btrfs subvolume delete /mnt/$subvol; done
+ btrfs subvolume set-default 0 /mnt
+ [[ ! -e /mnt/root_$DISTRO ]] || btrfs subvolume delete /mnt/root_$DISTRO
-## create subvols ##
-cd /mnt
-for x in q home_$DISTRO root_$DISTRO; do
- btrfs subvolume list . | grep "$x$" >/dev/null || btrfs subvolume create $x
+ ## create subvols ##
+ cd /mnt
+
+ btrfs subvolume create root_$DISTRO
+ [[ -e q ]] || btrfs subvolume create q
chown root:1000 q
-done
-mkdir -p /mnt/root_$DISTRO/boot
-for x in root/a q/a; do
- mkdir -p $x
- chown 1000:1000 $x
- chmod 755 $x
-done
-# could set default like this, but no reason to.
-# btrfs subvolume set-default \
- # $(btrfs subvolume list . | grep "root_$DISTRO$" | awk '{print $2}') .
-chattr -Rf +C root_$DISTRO
-cd /
-umount /mnt
+
+ mkdir -p /mnt/root_$DISTRO/boot
+ for x in q/a q/i; do
+ mkdir -p $x
+ chown 1000:1000 $x
+ chmod 755 $x
+ done
+ # could set default like this, but no reason to.
+ # btrfs subvolume set-default \
+ # $(btrfs subvolume list . | grep "root_$DISTRO$" | awk '{print $2}') .
+
+ # no cow on the root filesystem. it's setup is fully scripted,
+ # (immutable in buzzwords). if it messes up, we will just recreated it,
+ # and we can get better perf with this.
+ # I can't remember exactly why, but this is preferable to mounting with
+ # -o nodatacow, I think because subvolumes inherit that.
+ chattr -Rf +C root_$DISTRO
+ cd /
+ umount /mnt
+fi
+
mount -o subvolid=0 $first_boot_dev /mnt
cd /mnt
btrfs subvolume set-default 0 /mnt
-[[ ! -e /mnt/boot_$DISTRO ]] || btrfs subvolume delete /mnt/boot_$DISTRO
-btrfs subvolume create boot_$DISTRO
+
+# for libreboot systems
+mkdir -p /mnt/grub2
+cat >/mnt/grub2/libreboot_grub.cfg <<'EOF'
+#!/bin/sh
+# shebang is for editor file mode detection only
+
+if [ -s $prefix/grubenv ]; then
+ load_env
+fi
+
+set default="0"
+set timeout=1
+
+menuentry debianstable_bootstrap {
+ configfile /$1/boot/grub/grub.cfg
+}
+
+for dir in /boot_*; do
+ if [ x$dir = x$default_subvol ]; then
+ default=default_id
+ menuentry $dir --id=default_id {
+ configfile $1/grub/grub.cfg
+ }
+ else
+ menuentry $dir {
+ configfile $1/grub/grub.cfg
+ }
+ fi
+done
+EOF
+
+if [[ $DISTRO == debianstable_bootstrap ]]; then
+ # this is just convenience for the libreboot_grub config
+ # so we can glob the other ones easier.
+ boot_vol=$DISTRO
+else
+ boot_vol=boot_$DISTRO
+fi
+[[ ! -e /mnt/$boot_vol ]] || btrfs subvolume delete /mnt/$boot_vol
+btrfs subvolume create $boot_vol
cd /
umount /mnt
## end create subvols ##
-
-cat > /tmp/fai/fstab <<EOF
+if [[ $DISTRO == debianstable_bootstrap ]]; then
+ cat > /tmp/fai/fstab <<EOF
+$first_boot_dev / btrfs noatime,subvol=$boot_vol 0 0
+EOF
+ cat >/tmp/fai/disk_var.sh <<EOF
+BOOT_DEVICE="${short_devs[@]}"
+ROOT_PARTITION=$first_boot_dev
+EOF
+else
+ # note, the mount point /a seems to get automatically created somewhere
+ cat > /tmp/fai/fstab <<EOF
$first_root_crypt / btrfs noatime,subvol=root_$DISTRO 0 0
$first_root_crypt /q btrfs noatime,subvol=q 0 0
/q/a /a none bind 0 0
-$first_root_crypt /home btrfs noatime,subvol=home_$DISTRO 0 0
-$first_boot_dev /boot btrfs noatime,subvol=boot_$DISTRO 0 0
+$first_boot_dev /boot btrfs noatime,subvol=$boot_vol 0 0
EOF
-swaps=()
-for dev in ${devs[@]}; do
- swaps+=(`swap-cryptname`)
- cat >>/tmp/fai/crypttab <<EOF
+ # I will avoid using uuid in the future. the other way of specifying is simpler
+ if ifclass treetowl; then
+ cat >> /tmp/fai/fstab <<'EOF'
+$first_root_crypt /i btrfs noatime,subvol=i 0 0
+UUID=3f7b31cd-f299-40b4-a86b-7604282e2715 /i btrfs noatime 0 2
+EOF
+ fi
+
+ swaps=()
+ for dev in ${devs[@]}; do
+ swaps+=(`swap-cryptname`)
+ cat >>/tmp/fai/crypttab <<EOF
`root-cryptname` `rootdev` none keyscript=/root/keyscript,discard,luks
`swap-cryptname` `swapdev` /dev/urandom swap,cipher=aes-xts-plain64,size=256,hash=ripemd160
EOF
- cat >> /tmp/fai/fstab <<EOF
+ cat >> /tmp/fai/fstab <<EOF
`swap-cryptdev` none swap sw 0 0
EOF
-done
+ done
-# fai would do this:
-#BOOT_DEVICE=\${BOOT_DEVICE:-"${devs[0]}"}
+ # fai would do this:
+ #BOOT_DEVICE=\${BOOT_DEVICE:-"${devs[0]}"}
-# swaplist seems to do nothing.
-cat >/tmp/fai/disk_var.sh <<EOF
-ROOT_PARTITION=\${ROOT_PARTITION:-$first_root_crypt}
-BOOT_PARTITION=\${BOOT_PARTITION:-$first_boot_dev}
+ # note: swaplist seems to do nothing.
+ cat >/tmp/fai/disk_var.sh <<EOF
BOOT_DEVICE="${short_devs[@]}"
+BOOT_PARTITION=\${BOOT_PARTITION:-$first_boot_dev}
+# ROOT_PARTITIONS is added by me, used in arch setup.
+ROOT_PARTITIONS="${root_devs[@]}"
+ROOT_PARTITION=\${ROOT_PARTITION:-$first_root_crypt}
SWAPLIST=\${SWAPLIST:-"${swaps[@]}"}
EOF
+fi