#!/bin/bash
echo <<THIS_IS_NOT_A_SCRIPT

   this is an alpine linux installation guide
   for full disk encryption on uefi hardware using syslinux
   
   with an additional section dealing with i915-based gear
   (apollo-lake / 2016+ intel CPUs) which freeze the display
   as the bootloader enters the initramfs

   what we will NOT be using:
   -- lvm
   -- glibc
   -- systemd
   -- pulseaudio

   if you value the contents on your machine
   please don't actually run this as a script

   Alpine 3.7 was the most recent version as of writing,
   replace all instances of 3.7 with the current latest ver,
   see https://mirror.leaseweb.net/alpine/


   # HDD types
   this doc assumes you're installing to eMMC storage,
   commonly found in cheap gear. Determine your hardware
   (`lsblk` or `blkid`) and do a find/replace before starting:

                eMMC       NVMe       SATA
   entire disk  mmcblk0    nvme0n1    sdb
     boot part  mmcblk0p1  nvme0n1p1  sdb1
   system part  mmcblk0p2  nvme0n1p2  sdb2


   ver.3 (2018-03-29)
   └─ add Xfce instructions (later moved to xfce.sh)
   
   ver.2 (2018-03-28)
   └─ changed from grub to syslinux
   
   ver.1 (2018-03-27)
   └─ first version
   
   https://ocv.me/doc/?alpine/uefi-fde.sh  <ed@irc.rizon.net>
   
THIS_IS_NOT_A_SCRIPT
exit 1


# dd if=alpine-extended-3.7.0-x86_64.iso of=/dev/sdX bs=8k conv=sync,noerror
http://dl-cdn.alpinelinux.org/alpine/v3.7/releases/x86_64/alpine-extended-3.7.0-x86_64.iso


# unless the installation target has network access,
# copy these extra packages to another (ext2) memstick:
#   grub-efi, gptfdisk, sgdisk, wget
https://mirror.leaseweb.net/alpine/v3.7/main/x86_64/
https://mirror.leaseweb.com/alpine/v3.7/main/x86_64/gptfdisk-1.0.3-r0.apk
https://mirror.leaseweb.com/alpine/v3.7/main/x86_64/sgdisk-1.0.3-r0.apk
https://mirror.leaseweb.com/alpine/v3.7/main/x86_64/wget-1.19.2-r1.apk


# boot the alpine livecd on target and...
apk add e2fsprogs dosfstools util-linux \
	cryptsetup mkinitfs syslinux bash vim

bash
setup-apkcache /apks


# OPTION 1)
#   install the extra packages from usb
#   (if fat32, use -t vfat)
mount -t ext2 /dev/sdb1 /media/floppy
apk add /media/floppy/pkgs/*.apk


# OPTION 2)
#   install the extra packages from an httpd on your LAN,
#   for example a laptop which is running
#   `python3 -m http.server`  or  `python2 -m SimpleHTTPServer`
#   inside a folder which contains the required apk files
apk add curl
setup-interfaces
ifup wlan0
curl -O http://192.168.1.137:8000/wget-1.19.2-r1.apk
apk add wget-*
wget -Krl 1 -npvc -erobots=off http://192.168.1.137:8000/
apk add 192.168.1.137\:8000/*.apk


# OPTION 3)
#   install them from an alpine mirror on the internet
setup-interfaces
ifup eth0
setup-apkrepos
# use leaseweb as mirror, shift-pgup/pgdn to see its number
apk add grub-efi gptfdisk sgdisk wget


# if you have a partial installation
# that you want to continue work on:
cryptsetup luksOpen /dev/mmcblk0p2 rv
mount /dev/mapper/rv /mnt/
mount /dev/mmcblk0p1 /mnt/boot/
# stop reading at this point


# start by destroying all data on disk
sgdisk -Z /dev/mmcblk0


# make disk partitions,
# [brackets] = use default value (just hit enter)
echo <<MANUAL_INPUT_FOR_BELOW_COMMAND

	o         new empty guid part table
	y         yes

	n         create efi part (/boot)
	[1]       part number
	[2048]    first sector
	+95M      last sector
	ef00      hex code (efi system)

	n         create sys part (/)
	[2]       part number
	[196608]  first sector
	[61071326]
	[8300]    hex code (linux fs)
	
	w         write
	y         yes

MANUAL_INPUT_FOR_BELOW_COMMAND
gdisk /dev/mmcblk0


# p1 and p2 sometimes disappear, this fixes it
partprobe /dev/mmcblk0


# luks
cryptsetup -c aes-xts-essiv:sha256 \
	-h sha512 -s 512 -y -i 5000 luksFormat /dev/mmcblk0p2

cryptsetup luksOpen /dev/mmcblk0p2 rv


# filesystems
mkfs.vfat /dev/mmcblk0p1
mkfs.ext4 -T huge /dev/mapper/rv

mount -t ext4 /dev/mapper/rv /mnt
mkdir /mnt/boot
mount -t vfat /dev/mmcblk0p1 /mnt/boot
mkdir /mnt/boot/EFI


# alpine config
echo <<MANUAL_INPUT_FOR_BELOW_COMMAND

	us               keyboard layout
	us-altgr-intl    altgr+zlw = æøå
	kvit             hostname
	[eth0]           configure entwork device
	dhcp             ip address for [...]
	[no]             manual network cfg
	[]               dns domain
	1.1.1.1          dns nameserver
	*rootpwd*
	[UTC]            timezone
	[none]           proxy
	14               NOTE: use Leaseweb's number,
	                   find it with shift-pgup/pgdn
	none             sshd
	none             ntpd
	[none]           disk setup
	none             config store
	[/apks]          apk cache

MANUAL_INPUT_FOR_BELOW_COMMAND
setup-alpine

# write to disk, md5 sum provided to make sure there's no typos
echo 'USE_EFI=1 DISKLABEL=gpt BOOTLOADER=syslinux setup-disk -m sys /mnt' | md5sum
# b874c6bc6832b5ca850b1efbc7c8ff37

# this will end with a few error messages, including "ln: operation not permitted"
USE_EFI=1 DISKLABEL=gpt BOOTLOADER=syslinux setup-disk -m sys /mnt

# note that on recent alpine versions,
# this will produce a barrage of error messages regarding a memory leak
# since setup-disk tries and fails to set up grub...
# this is apparently harmless but should be avoided somehow, TODO


# create crypttab
echo 'rv /dev/mmcblk0p2 none luks' > /mnt/etc/crypttab


# fix video dropping out while in the initramfs
# (minimal version of kms.modules for i915)
cd /mnt/etc/mkinitfs/features.d/

cat > apollokms.modules <<EOF
kernel/drivers/gpu/drm/drm.ko
kernel/drivers/gpu/drm/drm_kms_helper.ko
kernel/drivers/gpu/drm/i915
kernel/drivers/char/agp/agpgart.ko
kernel/drivers/char/agp/intel-gtt.ko
kernel/drivers/char/agp/intel-agp.ko
kernel/drivers/video/console
kernel/drivers/video/fbdev/intelfb
kernel/arch/x86/video/fbdev.ko
EOF

echo 'features="ata base ide scsi usb ext4 cryptsetup apollokms mmc"' > ../mkinitfs.conf
# stuff that I removed:
#   'virtio' is only needed for virtual machines
#
# stuff that I added:
#   'cryptsetup' is needed to decrypt the rootfs
#   'apollokms' is needed by some i915 gear
#   'mmc' is needed by netbooks with 32gb/64gb "SSD" storage,
#         replace with nvme if your system is less crappy


# create the initramfs
# (copying to live-env /etc below is not an error)
cp apollokms.modules /etc/mkinitfs/features.d/
mkinitfs -c /mnt/etc/mkinitfs/mkinitfs.conf -b /mnt


# syslinux config
vim /mnt/etc/update-extlinux.conf
# default_kernel_opts:   nomodeset quiet => modeset noquiet
# default_kernel_opts += cryptroot=/dev/mmcblk0p2 cryptdm=rv grsec_sysfs_restrict=0
# vesa_menu = 1
#
# 'modules' below is probably pointless (and covered by initramfs)
# ...but just in case it was the magic fix after all:
# modules += drm,drm-kms-helper,i915,agpgart,intel-gtt,fbcon,mmc-block,mmc-core,video


# apply syslinux config
cp /mnt/etc/update-extlinux.conf /etc/
extlinux --install /mnt/boot/ --update


# check that it applied  (spoiler: it didn't)
grep el_opts= /etc/update-extlinux.conf >> /mnt/boot/extlinux.conf
vim /mnt/boot/extlinux.conf


# for comparison, the efi stuff from grub (v1 of this doc):
#   /boot/efi/EFI/alpine/grubx64.efi
#   /boot/efi/EFI/boot/bootx64.efi
#
# the vfat partition was mounted at /boot/efi
# so these are PROBABLY expected at /boot/EFI/xxx/yyy.efi


# install syslinux for efi
cd /mnt/boot
cp -pvR /usr/share/syslinux/efi64 EFI/boot
cp EFI/boot/syslinux.efi EFI/boot/bootx64.efi
cp extlinux.conf EFI/boot/syslinux.cfg

# in the EFI edition of the bootloader config,
# the initramfs and image must be prefixed by a slash
sed -ri 's@(LINUX|INITRD) (vmlinuz|initramfs)@\1 /\2@' EFI/boot/syslinux.cfg
diff extlinux.conf EFI/boot/syslinux.cfg


# shutdown
cd
umount /mnt/boot
umount /mnt
cryptsetup luksClose rv
sync
poweroff


##
## unplug the usb sticks and power back up
## then see xfce.sh
##
