Installing Gentoo on Lenovo M72e Tiny PC
It has been a very long time since I install Gentoo Linux on anything, so just noting in a blog post what I did. As always, the basic process is RTFM in the form of the Gentoo Handbook. In this post, I got as far as completing what I will call the “modern stage 1” (i.e. the process for rebuilding everything with an optimised toolchain, which used to be a “stage 1” install but became a “stage 3 with bootstrap.sh script” around 2010) but not configuring/building/installing the kernel and bootloader. Unfortunately I ran out of time to play with this and went back to Debian on the system, in order to get some other work done.
Preparation - enabling follow symlinks on NAS mirror
In order to enable the ‘latest-…’ symlinks to work, I had to enable following symlinks on the NAS I previously setup to act as a mirror server.
I edited /etc/frontview/apache/Shares.conf
:
<Directory "/c/mirrors">
Options FollowSymlinks
</Directory>
And then restarted the webserver:
/etc/init.d/frontview stop
/etc/init.d/frontview start
I suspect that the changes to Shares.conf
will get overwritten if I reconfigure any http-access to shares but, for now, this is working.
Choosing the right installation medium
As my machine was already booted from a Debian Live USB drive, I did the install from this.
Configuring the network
I am building this system in my air-gapped home lab, so there is not internet to download files from - however there is a local mirror (and my Debian Live systems is already connected to the network) which I will mount (later) for the source files.
Preparing the disks
I created a new GUID Partition Table (GPT) type partition table, added an EFI system partition (ESP) and partitioned the rest for and encrypted volume for LVM:
# parted /dev/sda
(parted) mklabel gpt
(parted) mkpart "EFI system partition" fat32 0% 512MiB
(parted) set 1 esp on
(parted) mkpart "encrypted container" ext4 512MiB 100%
(parted) set 2 lvm on
Setup encryption
cryptsetup luksFormat /dev/sda2
cryptsetup luksOpen /dev/sda2 lvm-base
Setup LVM
I had to install the lvm package, as it was not already available in my Debain live environment:
apt-get install lvm2 -n swap
I am creating the following partition scheme, which is my preferred choice:
- 15G -
/
(historically this would have been 10G/usr
and 5G/
butsystemd
objects to/usr
and/
being separate filesystems) - 10G -
/var
- 10G -
/home
- 5G -
/srv
- 5G -
/opt
- 5G -
/tmp
N.B. I use the hostname for the volume group name, it is helpful to do this in case it needs mounting on another machine (e.g. for recovery) to avoid clashing volume names.
pvcreate /dev/mapper/lvm-base
vgcreate create sovereign /dev/mapper/lvm-base
lvcreate -L 16G -n swap sovereign
lvcreate -L 15G -n root sovereign
lvcreate -L 10G -n var sovereign
lvcreate -L 10G -n home sovereign
lvcreate -L 5G -n srv sovereign
lvcreate -L 5G -n opt sovereign
lvcreate -L 5G -n tmp sovereign
Setup filesystems
The Gentoo handbook page on preparing disks says to specify -T small
to mkfs.ext4
for partitions less than 8GiB in size. The mkfs.ext4
handbook says this is for partitions less than 512 megabytes - which is much smaller than 8 GiB.
mkfs.vfat -F 32 /dev/sda1
mkswap -L swap /dev/mapper/sovereign-swap
for fs in var home srv opt tmp root
do
mkfs.ext4 -L $fs /dev/mapper/sovereign-$fs
done
Mount the filesystems
swapon /dev/mapper/sovereign-swap
mkdir /mnt/gentoo
mount /dev/mapper/sovereign-root /mnt/gentoo
mkdir -p /mnt/gentoo/{boot/EFI,var,home,srv,opt,tmp}
mount /dev/sda1 /mnt/gentoo/boot/EFI
for fs in var home srv opt tmp
do
mount /dev/mapper/sovereign-$fs /mnt/gentoo/$fs
done
chmod 1777 /mnt/gentoo/tmp
Installing the stage tarball
The Gentoo handbook’s page tells us to being by setting the date. Since I now have an NTP source in my air-gapped network, I just used that:
apt-get install ntpdate
ntpdate ntp
Download the tarball (noting I already made a mirror of it locally):
apt-get install wget
cd /tmp
wget http://mirror/mirrors/gentoo/latest-stage3-amd64-nomultilib-systemd.tar.xz
Extract the tarball:
tar -C /mnt/gentoo -xpvf /tmp/latest-stage3-amd64-nomultilib-systemd.tar.xz --xattrs-include='*.*' --numeric-owner
Configure the system variables
In /etc/portage/make.conf
I set COMMON_FLAGS
and added MAKEOPTS
(for parallel makes, set to number of CPU threads) & PORTAGE_RO_DISTDIRS
(for the aforementioned local mirror):
COMMON_FLAGS="-march=native -O2 -pipe -ftree-vectorize -funroll-loops"
# ...
MAKEOPTS="-j2"
# ...
PORTAGE_RO_DISTDIRS="/var/cache/distfiles_mirror"
# ...
And mounted the mirror:
mkdir /mnt/gentoo/var/cache/distfiles_mirror
mount -t nfs -o ro mirror:/mirror/gentoo/distfiles /mnt/gentoo/var/cache/distfiles_mirror
Chrooting
Configure mirrors
Because I am using local sources, I do need to do some mirror selection. By NFS mounting the dist files, no downloading should be necessary (and portage attempting to go off an fetch a source indicates a problem with my setup, which needs rectifying) so setting a distfiles mirror is unnecessary but the ebuild repository needs to be got from the local mirror:
mkdir /mnt/gentoo/etc/portage/repos.conf
cp /mnt/gentoo/usr/share/portage/config/repos.conf /mnt/gentoo/etc/portage/repos.conf/gentoo.conf
Then edit /mnt/gentoo/etc/portage/repos.conf/gentoo.conf
(I changed sync-uri
to my mirror and added sync-openpgp-key-refresh = no
to stop it trying to get keys from Gentoo’s key server):
[DEFAULT]
main-repo = gentoo
[gentoo]
location = /var/db/repos/gentoo
sync-type = rsync
sync-uri = rsync://mirror/mirrors/gentoo/portage-db/gentoo
auto-sync = yes
sync-rsync-verify-jobs = 1
sync-rsync-verify-metamanifest = yes
sync-rsync-verify-max-age = 24
sync-openpgp-key-path = /usr/share/openpgp-keys/gentoo-release.asc
sync-openpgp-keyserver = hkps://keys.gentoo.org
sync-openpgp-key-refresh = no
sync-openpgp-key-refresh-retry-count = 40
sync-openpgp-key-refresh-retry-overall-timeout = 1200
sync-openpgp-key-refresh-retry-delay-exp-base = 2
sync-openpgp-key-refresh-retry-delay-max = 60
sync-openpgp-key-refresh-retry-delay-mult = 4
sync-webrsync-verify-signature = yes
Copy DNS information
cp --dereference /etc/resolv.conf /mnt/gentoo/etc/resolv.conf
Mount necessary filesystems
From the Gentoo handbook page:
The
--make-rslave
operations are needed for systemd support later in the installation.
mount -t proc none /mnt/gentoo/proc
mount --rbind /sys /mnt/gentoo/sys
mount --make-rslave /mnt/gentoo/sys
mount --rbind /dev /mnt/gentoo/dev
mount --make-rslave /mnt/gentoo/dev
mount --bind /run /mnt/gentoo/run
mount --make-slave /mnt/gentoo/run
Entering the new environment
(At least this stage has not changed since I last used Gentoo ;) ):
chroot /mnt/gentoo /bin/bash
source /etc/profile
export PS1="(chroot) ${PS1}"
Configure portage
Now we get to test if the ebuild mirror is configured correctly:
emerge --sync
The handbook recommends updating world at this point, which is a good point to test if our read-only distfiles mirror is working:
emerge -avuDN @world
I encountered a couple of problems doing this (so it was a good sanity-check):
- initially the first build failed with “C compiler cannot make executables”, so I checked my
/etc/portage/make.conf
- turned out I had spelledvectorize
asvectorise
(my native, British English, spelling). Correcting that and it installed just fine. - missing sources for
net-misc/iputils
, so added that explicitly to the packages downloaded by my mirror Ansible playbook
Setup USE
in /etc/portage/make.conf
:
USE="X alsa doc"
Setup CPU_FLAGS_*
- from the Gentoo handbook :
emerge -av app-portage/cpuid2cpuflags
echo "*/* $(cpuid2cpuflags)" > /etc/portage/package.use/00cpu-flags
Set VIDEO_CARDS
in /etc/portage/make.conf
for this machine’s hardware:
VIDEO_CARDS="fbdev vesa intel"
Configure the system
systemd-firstboot --prompt --setup-machine-id
systemctl preset-all
ln -sf ../usr/share/zoneinfo/Europe/London /etc/localtime
Configure locales by setting /etc/locale.conf
:
LANG="en_GB.UTF-8"
LC_COLLATE="C.UTF-8"
and /etc/locale.gen
:
en_GB UTF-8
before running:
locale-gen
env-update && source /etc/profile && export PS1="(chroot) ${PS1}"
Bootstrapping
Per the Gentoo FAQ, this stage is performed before proceeding to configuring the kernel.
cd /var/db/repos/gentoo/scripts
There is a bug in the current script, according to Sakaki’s EFI Install Guide so make the change they suggest:
The second problem is that, for modern versions of gcc, we need to allow the openmp USE flag. With the /var/db/repos/gentoo/scripts/bootstrap.sh file still open, issue Ctrlw to start a second search, and then type export USE=”- and press Enter. Modify the line selected by adding openmp at the end, so it now reads:
export USE="-* bootstrap ${ALLOWED_USE} ${BOOTSTRAP_USE} openmp"
Note As this file exists as part of the main Gentoo ebuild repository, your changes will be overwritten next time you sync. As we only want to bootstrap our system now, that’s not a problem (but you can of course make a copy of the modified bootstrap.sh file at this point, should you wish).
cp /etc/locale.gen{,.bak}
time ./bootstrap.sh
This took around 5 minutes for me. Next, check the rebuilt compiler is valid:
gcc-config --list-profiles
Run bootstrap again to rebuild with the optimised toolchain:
time ./bootstrap.sh
# Pure sanity check - if it did not break the first time, should be fine here:
gcc-config --list-profiles
mv /etc/locale.gen{.bak,}
locale-gen
env-update && source /etc/profile && export PS1="(chroot) ${PS1}"
Rebuild all of the packages:
touch /tmp/prebuild_checkpoint # Used to check everything has been updated, after the build
# The 'doc' flag I added creates dependency loops, which will need to be resolved later
USE="-doc" emerge -ave @world
dispatch-conf # Review any configuration files the need updating
Verify everything was rebuild successfully, by removing unnecessary dependencies then checking for files older than our /tmp/prebuild_checkpoint
file.
# Remove anything not in the dependency tree
emerge --depclean
# If every executable on the system has been rebuilt, this command should produce no output
find / -type d -path /boot/efi -prune -o -path /proc -prune -o -type f -executable -not -newer /tmp/prebuild_checkpoint -print0 2>/dev/null | xargs -0 file --no-pad --separator="@@@" | grep -iv '@@@.* text'
# If every file recognised by `file` as a libarary (ELF or archive) has been rebuilt, this command should produce no output
find / -type d -path /boot/efi -prune -o -path /proc -prune -o -type f -not -executable -not -newer /tmp/prebuild_checkpoint -print0 2>/dev/null | xargs -0 file --no-pad --separator="@@@" | grep '@@@.*\( ELF\| ar archive\)'