Slackware 15.0 on the Framework

the ideal combination?

Yep, perfect combination indeed.

So Slackware 15.0 finally released after what felt like an eternity. I happen to have one of those newfangled Framework laptops, which was currently happily running openSUSE Tumbleweed, and I figured I was overdue to come back home to my tried and true distro, so here goes.

Slackware? Really?

Yes, really. I’m a relative latecomer to the Slackware community (I first tried it when 14.0 was the current version), but it immediately felt like home, and that feeling hasn’t really gone away.

I just think it’s a neat distro. It’s one of the few that makes it a point to stay out of the user’s way, and I definitely appreciate that. It’s nice having a (GNU/)Linux distro that’s as close to “vanilla” as a distro gets, and it’s nice not having to fight with some fancy-shmancy dependency-resolving package manager (the software packaging process is so barebones and straightforward that I’ve even contributed my share of Slackbuilds to that effect, though admittedly I’ve slacked off (pun absolutely intended) on keeping ‘em up to date, so maybe this will be the kick in the butt I need to get back on that). Being the oldest actively-maintained distro is also cool in its own right.

For the above reasons (among many, many others), it’s the one and only GNU/Linux distro for which I’ve ever paid actual money, and that money is well worth it; Pat Volkerding and the rest of the Slackware team have all done a fantastic job over the decades, and they deserve every penny (which makes it all the more heartbreaking to hear how hard Pat got financially fucked over, and all the more imperative to donate echo "$(cat /etc/slackware-version | awk '{print $2}')" USD, sponsor, and/or buy merch).

Framework?

In terms of build quality, compatibility, repairability, and extensibility, the Framework’s hard to beat. The 3:2 screen is fantastic; using a Pixelbook left me wondering why other laptop designs don’t deviate from boring ol’ 16:9 / 16:10, and here comes Framework hitting a home run. The whole “USB-C expansion ports” dealio is fantastic, and I look forward to seeing a proliferation of zany expansion port ideas by the community (and possibly myself if I can think of any). The build quality puts Apple to shame, and they do it with a design that’s easy to repair without any signfiicant compromise in compactness, and they throw in a much nicer keyboard to boot (get outta here with that butterfly switch nonsense). The camera and microphone switches are pretty neat, too, and it’s great knowing that if any part breaks I can order a new one and fix it myself. This is, put simply, a machine built to last, and it has served me well (and, I expect, will continue to do so for quite some time).

While Framework doesn’t (last I check) offer any Linux distros as preinstall options, they’ve made it a point to support Linux on their hardware, and it shows: openSUSE worked flawlessly out of the box as far as I was able to tell, and I’ve heard from the grapevine that plenty of other distros do, too. Is Slackware one of ‘em? Only one way to find out…

Let’s do it!

For the most part this was a pretty standard Slackware install, but I did do a couple oddball things.

Pre-installation steps

Obviously I needed to download Slackware’s ISO from my friendly neighborhood Slackware mirror, and I needed to get that written to a thumbdrive (sudo dd if=~/Downloads/slackware64-15.0-install-dvd.iso of=/dev/sdb bs=512 status=progress did the trick). A reboot and some mashing of the F12 key later, and I had the Slackware installer’s GRUB menu before me. Default choice worked fine, as did the default keymap, so now I had before me an all-too-familiar prompt to login as root and start installing things.

Now, for those of y’all who ain’t familiar with Slackware’s install process, it doesn’t really hold your hand through setting up disks; when you actually run the setup command, it expects you to have already setup your partitions as desired. Back in the day, this was easy-peasy-lemon-squeezy: you just create a new MBR, make a root partition, make a swap partition, and you’re all set, but it’s 2022 and things have evolved. We’ve got ourselves a UEFI-capable machine, after all, and this is a laptop so full-disk encryption is pretty much mandatory - which means using LUKS (and LVM, because decrypting a bunch of individual partitions is for suckers).

Thankfully, the Slackware install media ships with instructions to that effect: README_CRYPT.TXT and README_UEFI.TXT guide a prospective user through the process of setting up LUKS+LVM and UEFI booting (respectively); and the latter even guides you through keeping Windows as a dual-boot option if so desired. Having done plenty of Slackware installations in the past, the usual sequence would’ve been pretty much muscle memory:

cfdisk  # Wherein I create 500MB EFI + 500MB Linux + rest Linux partitions
mkfs.fat /dev/nvme0n1p1
mkfs.ext2 /dev/nvme0n1p2
dd if=/dev/urandom of=/dev/nvme0n1p3
cryptsetup -y luksFormat /dev/nvme0n1p3
cryptsetup luksOpen /dev/nvme0n1p3 luksnvme0n1p3
pvcreate /dev/mapper/luksnvme0n1p3
vgcreate cryptvg /dev/mapper/luksnvme0n1p3
lvcreate -L 32G -n swap cryptvg
lvcreate -L 350G -n root cryptvg
mkswap /dev/cryptvg/swap
mkfs.xfs /dev/cryptvg/root

But this time was a bit different:

So, seeing as I already had a GPT setup on my /dev/nvme0n1, with an EFI partition and LUKS partition I wanted to reuse, I broke from muscle memory for a bit this time:

cryptsetup luksOpen /dev/nvme0n1p2 luksnvme0n1p2
vgremove system  # Technically unneccesary, but whatever
vgcreate cryptvg /dev/mapper/luksnvme0n1p2
lvcreate -L 32G -n swap cryptvg
lvcreate -L 100G -n root cryptvg
lvcreate -L 250G -n home cryptvg
mkswap /dev/cryptvg/swap
# GRUB doesn't like casefolding and other fancy features, so we're
# keeping root vanilla
mkfs.ext4 /dev/cryptvg/root
# /home, on the other hand, gets casefolding.  It also gets 64-bit
# support, because mkfs.ext4 warned about that and "full-strength
# checksumming" seems like a pretty good idea.
mkfs.ext4 -O casefolding,64bit /dev/cryptvg/home

Actually running the installer

Installing Slackware's packages on my
Framework

With my partitions squared away, it was time to actually run the setup command, presenting me with the nice eye-melting blue-backgrounded curses interface I had grown to love (it’s an acquired taste, I swear). Added /dev/cryptvg/swap as swap, added /dev/cryptvg/root as /, and added /dev/cryptvg/home as /home.

It was at this point I noticed that Slackware’s installer detected the wrong EFI partition; instead of the one on my NVMe drive, it had picked the one on the thumbdrive. Easy to fix: just hopped over to another TTY, ran a quick umount /mnt/boot/efi + mount /dev/nvme0n1p1 /mnt/boot/efi, and noted to myself that I’d need to edit /mnt/etc/fstab after the installer finishes.

After that point, it was all a pretty smooth and standard (if there is such a thing) Slackware install: picked my USB stick as my source, left everything selected, picked the terse option, and waited for a few minutes as various package descriptions scrolled across the screen.

I skipped the USB stick creation step, and I skipped both LILO and ELILO (normally I would’ve used one or the other - in this case ELILO, since I intended to boot via UEFI - but neither supports LUKS or LVM (let alone both) like GRUB does, so both got the axe this time). I picked the USB mouse option and enabled gpm (these don’t matter for X11 or Wayland, but they allow using the mouse in the otherwise-text-only Linux console, which is cool so I always do it), skipped the network config (I was gonna use NetworkManager anyway, since it’s a laptop and would be roaming around), stuck with the default daemons and fonts, set the hardware clock to UTC, set the timezone to US/Pacific, set the default graphical session to KDE, and set the root password.

Done with setup now, but naturally there were a few things I still needed to do.

Post-installation steps

First things first: ran chroot /mnt, then edited /etc/fstab to fix that incorrect /boot/efi detection:

/dev/cryptvg/swap swap             swap        defaults         0   0
/dev/cryptvg/root /                ext4        defaults         1   1
/dev/cryptvg/home /home            ext4        defaults         1   2
/dev/nvme0n1p1    /boot/efi        vfat        defaults         1   0
#/dev/cdrom      /mnt/cdrom       auto        noauto,owner,ro,comment=x-gvfs-show 0   0
/dev/fd0         /mnt/floppy      auto        noauto,owner     0   0
devpts           /dev/pts         devpts      gid=5,mode=620   0   0
proc             /proc            proc        defaults         0   0
tmpfs            /dev/shm         tmpfs       nosuid,nodev,noexec 0   0

Normally, this is where I would create an initrd.gz. However, turns out that Slackware 15.0 does this automatically now (at least as evidenced by the existence of /boot/initrd.gz and /boot/initrd-tree/). Pretty neat!

In any case, I needed to configure and install GRUB, and I wanted to make sure I included everything I needed in my initrd.gz:

echo 'GRUB_ENABLE_CRYPTODISK=y' >> /etc/default/grub
echo 'GRUB_CMDLINE_LINUX="cryptdevice=/dev/nvme0n1p2:lvm"' >> /etc/default/grub
grub-mkconfig -o /boot/grub/grub.cfg
grub-install /dev/nvme0n1
dd bs=512 count=4 if=/dev/urandom of=/boot/cryptkey.bin
cryptsetup luksAddKey /dev/nvme0n1p2 /boot/cryptkey.bin
echo 'MODULE_LIST="ext4:hid:drm:usbhid"' >> /etc/mkinitrd.conf
echo 'LUKSDEV="/dev/nvme0n1p2"' >> /etc/mkinitrd.conf
# Turns out this didn't actually work :(
echo 'LUKSKEY="/boot/cryptkey.bin"' >> /etc/mkinitrd.conf
echo 'ROOTDEV="/dev/cryptvg/root"' >> /etc/mkinitrd.conf
echo 'RESUMEDEV="/dev/cryptvg/swap"' >> /etc/mkinitrd.conf
echo 'LVM=1' >> /etc/mkinitrd.conf
mkinitrd -F -c -k 5.15.19
mkdir /boot/efi-backup
# Just in case...
mv /boot/efi/EFI/boot /boot/efi-backup/boot
mv /boot/efi/EFI/opensuse /boot/efi-backup/opensuse

And with that, I was finally ready to reboot for the first time (and ready to unplug the thumbdrive).

First-boot configuration

Right away, I noticed that GRUB did indeed install correctly (and I even blew away the original openSUSE-installed GRUB entirely, so this was clearly Slackware’s GRUB); after entering my LUKS passphrase at the prompt I got Slackware’s GRUB menu. I had to dig into the “advanced” submenu and pick the generic kernel instead of huge (long story short: you should always use generic instead of huge because generic uses an initrd.gz and huge doesn’t, and I forgot to skip installing the huge kernel like I normally do so I knew I’d have to clean that up at some point), but it did indeed boot as expected.

…well, mostly. You notice those couple of commands up above to create a LUKS key and try to include it in the initrd.gz? Well, turns out the LUKSKEY config option doesn’t work that way; that option only tells init to check for a file that’s visible during boot, and doesn’t tell mkinitrd to actually include it in initrd.gz (which is usually sensible, since Slackware’s usual assumption is that initrd.gz is in an unencrypted /boot partition, in which case baking in a LUKS key would entirely defeat the purpose of full-disk encryption). So, despite my best efforts, I ended up with a second passphrase prompt. Oh well. Ain’t the end of the world.

After reentering my passphrase, the first boot went perfectly smooth. Did my normal post-install steps (useradd northrup and added myself to wheel and dialout; uncommented sudo permissions for wheel members in /etc/sudoers; changed default runlevel from 3 to 4 in /etc/inittab; ran chmod +x /etc/rc.d/rc.networkmanager because I forgot to tick that option in the installer), uncommented kernel-huge.* in /etc/slackpkg/blacklist, ran removepkg kernel-huge, re-ran grub-mkconfig -o /boot/grub/grub.cfg, and gave it another reboot.

So does it work?

Writing this blog post on Slackware 15.0 on my
Framework

Sure does :)

Slackware 15.0 is the first release to include Wayland and PipeWire, so naturally those were the first things I tried out, and both work perfectly: Wayland was as simple as picking the relevant option at the login screen, and PipeWire was as simple as running sudo /usr/sbin/pipewire-enable.sh and rebooting.

Suspend and resume work out-of-the-box. Wireless works out-of-the-box. Touchpad works out-of-the-box (including KDE’s multitouch gestures for things like presenting windows/desktops). Audio works out-of-the-box. 3D acceleration works out-of-the-box. Media keys work out-of-the-box. None of this is terribly surprising, seeing as how these worked out-of-the-box with openSUSE using an older kernel than what Slackware 15.0 uses, but the fact that it’s Slackware, of all things, working out of the box is still a wonderful feeling.

As for actually using it as my new daily driver, I’m already up and running with my usual development tools (Emacs, asdf w/ direnv) and applications (Firefox, Thunderbird). Slackpkg+ already fully supports Slackware 15.0, and all of the usual repos I use have 15.0 versions as well (most importantly: multilib/compat32, which is essential for running the smattering of 32-bit applications out there, including Steam).

Naturally, it ain’t all sugarcubes. SlackBuilds.org doesn’t seem to be particularly aware of the new version yet, nor does sbopkg, but hopefully that’ll come soon (and this is another reminder to myself to test/update the SlackBuilds I maintain to ensure 15.0 compatibility). Enabling PipeWire’s JACK support was a bit trickier than I expected but after some banging of my head against the wall it now works great with Ardour. As for including the LUKS key in initrd.gz, I first tried just shoving it into /boot/initrd-tree/boot/cryptkey.bin and re-running mkinitrd -F -k 5.15.19, which “worked” in the sense that the file is present in the initial ramdisk, but I still needed to tweak /boot/initrd-tree/init a bit (separate post incoming for that).

Other than those mild snags, I’d say it went about as perfectly as I’d hoped, and I can think of fewer better combinations than a tinkerer-friendly OS on a tinkerer-friendly laptop. Feels good to be back home :)