1
3
Fork
You've already forked kx
0
Experimental Linux distro, a mashup of KISS Linux and NixOS.
  • Python 100%
Steve Folta 42e083e2b7 README.md: corrected the bit about ntpd.
You don't need openntpd (which uses /etc/ntpd.conf instead of /etc/ntp.conf
anyway), there's already an ntpd in busybox.
2024年07月06日 00:47:08 +00:00
utils utils/check-kx-link: fixed to work in real KX stores. 2024年06月01日 19:48:40 +00:00
install-kx-to install-kx-to: making /var/tmp world-writeable. 2024年06月04日 23:19:49 +00:00
kx Improved display of conflicts. 2024年06月14日 22:20:16 +00:00
kx-wrap-python kx-wrap-python: $PYTHONPATH includes the existing one. 2024年05月27日 08:02:07 +00:00
README.md README.md: corrected the bit about ntpd. 2024年07月06日 00:47:08 +00:00

KX

KX is an experimental Linux distro that attempts to combine the virtues of KISS Linux and NixOS. It's essentially KISS Linux with a Nix-style package store.

And at this point, that's about all it is. So it has given up a bit of the Simplicity of KISS Linux, but it doesn't yet have the magical capabilities of NixOS. You can roll back to a previous generation, but you can't: configure a whole system with a single text file; rollback from the bootloader; use a binary cache; build minimal containers; cross-compile; etc. But it's a step toward enabling some or all of those things, hopefully without ending up as scattered and incomprehensible as Nixpkgs.

As in NixOS, in KX there is no "/usr/lib" (or "/lib"). There is, however, a fully populated "/usr/bin" and "/usr/share" -- it's just that these are managed by KX. But the user owns "/etc" (although the initial install does set up some things by default).

Trying it out

Let's give it a try in qemu. Along the way, we'll get familiar with some of the basic commands. First, download the live ISO. Make a directory somewhere and move the kx-live.iso file there. In this example, we're going to install it to a qemu disk image, so create that image, something like this:

$ qemu-img create -f qcow2 kx.image 32G

(If you're not familiar with qemu, don't worry -- this will not immediately take up 32G on your hard drive. A qcow2 image file is sparse, so it'll only use as much space as you end up filling up.)

Next, create a little script to run it, something like this (adjust to taste):

#!/usr/bin/env sh

# Edit or comment out as needed.
ISO="-cdrom kx-live.iso -boot order=d"
DISK="-drive file=kx.image,format=qcow2"
MEM="-m 4G"
SMP="-smp $(nproc)"
NET="-nic user,hostfwd=tcp::60022-:22"
qemu-system-x86_64 -enable-kvm $MEM $SMP $ISO $DISK $NET $@

Don't forget to do chmod +x on it. Then run it, and it should boot into the live KX image. This will take a little while. First it'll take the bootloader some time to load the initramfs, and even longer for the kernel to decompress it. But eventually you should have a login prompt, and you'll see dhcpcd getting the networking set up. Log in as "root"; the password is "kx-root".

Start by setting up the KX and KISS repos that supply all the packages. There's a script there to do that, so run it like this: ./clone-repos.

One of the things we'll need when we install KX is a bootloader. Let's use Limine... but that's not already installed in the live environment. No problem, we'll just build it. Type this:

$ kx install limine

Limine and its dependencies are built and installed.

Next, use fdisk /dev/sda to partition the hard disk. Create a "boot" partition for the bootloader, 64M is plenty for that (n, p, 1, return, +64M). Set its type to "EFI (FAT-12/16/32)" (t, ef). Then fill up the rest of the disk with another partition (n, p, 2, return, return). Then w to write out the partition table and exit.

Now we need to make the filesystems. What's the name of the package that has "mkfs.ext4"? I remember it has "e2fs" in its name... Do kx search e2fs... oh, it's called "e2fsprogs". Similarly, we need to create a FAT32 filesystem as well. Something about "DOS"... kx s dos (you can abbreviate the "search" to just "s", or "install" to just "i")... "dosfstools". So let's install those: kx i e2fsprogs dosfstools. Now we can make the filesystems:

$ mkfs.fat -F 32 /dev/sda1
$ mkfs.ext4 /dev/sda2

Now we can install KX to the main partition:

$ mount /dev/sda2 /mnt
$ install-kx-to /mnt

Let's copy that script to clone the repositories over as well:

$ cp clone-repos /mnt/root/

Now let's start setting up the bootloader:

$ umount /mnt
$ limine bios-install /dev/sda
$ mount /dev/sda1 /mnt
$ cp /usr/share/limine/limine-bios.sys /mnt/

We also need a Linux kernel there! We could build one (kx i kernel-basic && cp $(kx where kernel-basic)/bzImage /mnt/), but that would take a long time. The ISO already has a perfectly good one, so let's steal it from there:

$ mkdir /mnt-iso
$ mount -o ro /dev/sr0 /mnt-iso
$ cp /mnt-iso/bzImage /mnt/

While we're at it, let's grab a couple of other things as well. This is optional:

$ cp /mnt-iso/limine.cfg /mnt-iso/kx.png /mnt/

We'll need to edit that "/mnt/limine.cfg". "vi" is available, or do kx i nano if you don't like "vi". If you copied the "limine.cfg" from the ISO, delete the "MODULE_PATH" line and edit the "CMDLINE" line so it reads CMDLINE=root=/dev/sda2. If you're starting from scratch, this is all you really need:

:KX
PROTOCOL=linux
KERNEL_PATH=boot:///bzImage
CMDLINE=root=/dev/sda2

We're ready to run our new installation! Do poweroff. Now, back in the host, edit that script that runs qemu. Comment out the "ISO" line, which is like ejecting a CDROM. Then run the script again. Now we're running off the disk image that you just installed KX to. It should boot a lot faster this time. Log in as root again, same password ("kx-root"). Now would be a great time to use passwd to change the root password. And definitely set up the repos:

$ ./clone-repos

At this point the system should be ready to use. Perhaps you want to make sure everything is up-to-date:

$ export MAKEFLAGS="-j$(nproc)"
$ kx upgrade

If it says "Using: generation-1" at the end, it means none of the packages had updates. In the future, you can use kx update to update the repos, before doing a kx upgrade.

You may want to do things like adding new users...

$ adduser -G wheel joeyjojo

...letting users in the "wheel" group use "doas" (which is roughly the equivalent of "sudo")...

$ kx install opendoas
$ echo "permit nopass :wheel" >> /etc/doas.conf

...installing software (you've already met "kx search" and "kx install"); turning on services like ntpd (which is already available as part of busybox)...

$ for NUM in 0 1 2 3; do echo "server $NUM.pool.ntp.org" >> /etc/ntp.conf; done
$ ln -s /etc/sv/ntpd /var/service/

...(see this page for more about that); etc.

$KX_PATH

Like KISS, the location of the repositories that KX uses is specified by an colon-separated environment variable, in this case $KX_PATH. Unlike KISS, there is a default value for it, which is /kx/repos/kx:/kx/repos/kiss/core:/kx/repos/kiss/extra:/kx/repos/kiss-community/community. That's how that clone-repos script sets them up, but you can put them whereever you'd like, as long as you set $KX_PATH accordingly. If you start making packages, you'll probably put your own repo at the head of that list.

Making new packages

KX uses the same format for packages as KISS. In many cases, packages from the KISS repositories can be -- and are -- used. But, as a store-based system, KX is far less tolerant of undeclared dependencies. And sometimes things need to be done differently for a store-based distro, so the "build" scripts have some more things available to them:

$PREFIX is set to the eventual location of the package in the store. ($KX_PACKAGE_STORE_DIR is set to the same thing, but use of $PREFIX is preferred, as perhaps other similar distros will arise in the future, and $PREFIX is a non-distro-specific name.) If the package wants to hard-code its location in its files, you should configure it with "--prefix=$PREFIX". Otherwise, KX doesn't care whether the package installs to "/bin" or "/usr/bin".

$DESTDIR is the temporary directory to install to, before it gets moved to the store -- this is the same as the first argument to the script. $KX_LIB_DIRS is a colon-separated list of the library directories of the package's dependencies. Normally you won't need that, because the build system will take care of that for you automatically most of the time, but it's there if special circumstances require it.

In addition to what's listed in the package's "depends" file, every package is implicitly dependent on the libc (that is, on musl) and on the compiler's (that is, gcc's) libraries. But if a file named "c-only" exists in the package directory, the package won't have the compiler libraries as a dependency.

The original KISS Linux would replace several "marker" strings in the "sources" file with values parsed from the "version" file (VERSION, RELEASE, MAJOR, MINOR, PATCH, IDENT, and PACKAGE). Community KISS has removed that, but it's still available in KX.

For Python scripts, have your "build" script call "kx-wrap-python" at the end. That'll "wrap" the Python scripts in the "bin" directory so they get access to all they Python libraries they need.

The "post-install" and "pre-remove" scripts are not supported.

Alternatives

Like Community KISS Linux, KX supports "alternatives" to let you choose which files to use when two packages try to supply the same file. For instance, suppose you want to use the "mdev-conf" to manage your /dev. When you install it (kx install mdev-conf-git), you'll see a message indicating that there are two packages supplying the "etc/mdev.conf" file. You can specify the new one by doing kx alternatives mdev-conf-git etc/mdev.conf. kx alternatives (with no more arguments) will list all the current choices.

Quirks

  • Removing a package ("kx remove") can end up building others. That's because it currently works by just building a new environment/generation that doesn't include the package.
  • The Python building process is not very well thought out. Every single Python-based package in the KISS repos had to be forked to build successfully. I'm sure a knowledgeable person could come up with something better, but I can't bring myself to become an expert in the Python packaging quagmire. (I've written plenty of Python code, but I always stick to the included batteries.)
  • As mentioned above, there's still a fully-populated /usr/bin and /usr/share, instead of just putting the current environment/generation in everyone's $PATH (and $MANPATH and whatever other environment variables) like Nix does. TBH, I don't quite remember how it ended up that way; perhaps it's just a temporary phase.