305 lines
14 KiB
Markdown
305 lines
14 KiB
Markdown
|
lix-os
|
||
|
======
|
||
|
|
||
|
a linux distribution for people who like to breathe manually.
|
||
|
|
||
|
this repository contains documentation and helper scripts only. a working linux
|
||
|
distribution with overlayfs support (preferably alpine linux) and an internet
|
||
|
connection are required to bootstrap lix os. no images or binaries supplied.
|
||
|
|
||
|
## about
|
||
|
|
||
|
lix os uses the lix package manager to construct a musl-based linux distribution
|
||
|
from source code. it is entirely composed of simple, short-as-possible,
|
||
|
POSIX-compliant shell scripts. packages are built in chroots constructed from
|
||
|
package directories stacked on top of each other using overlayfs. only
|
||
|
dependencies explicitly listed in a package's 'deps' file are accessible during
|
||
|
the package's build process. there is no concept of "indirect dependencies."
|
||
|
packages are made available to the user by soft-linking package directory
|
||
|
contents into the system root. packages can be added to or removed from the
|
||
|
system root without uninstalling the packages entirely.
|
||
|
|
||
|
lix os is the work of a single maintainer and follows the same "use fewer
|
||
|
packages" ethos that kiss linux does. it also tries to use the smallest
|
||
|
packages possible in order to create a more readily audited codebase. some
|
||
|
exceptions are made in the name of usefulness and self-hosting. generally,
|
||
|
suckless utilities are preferred to bsd utilities, and bsd utilities are
|
||
|
preferred to gnu utilities due to the preferred in each case generally having a
|
||
|
smaller, easier to understand codebase. this does mean lix os's versions of
|
||
|
common linux utilities may have fewer options than one may be used to, but many
|
||
|
of these missing options are either not commonly used or can be compensated for
|
||
|
with a short shell script or function.
|
||
|
|
||
|
in the opinion of lix os' maintainer, it would be ideal if everyone knew and
|
||
|
understood every line of code executing on their machines. while a perfect
|
||
|
realisation of this dream is unlikely, lix hopes to make the problem less
|
||
|
intractable. lix os will never ship binaries.
|
||
|
|
||
|
## caveats
|
||
|
|
||
|
lix os is an experimental linux distribution. it may not work. it may catch on
|
||
|
fire. it may be abandoned at a moment's notice for another experiment. it will
|
||
|
not stop you from doing something stupid and destroying your system. it is not
|
||
|
and probably never will be "production ready."
|
||
|
|
||
|
nonetheless, the original author currently uses it daily, and it may serve the
|
||
|
needs of others as well.
|
||
|
|
||
|
## goals
|
||
|
|
||
|
1) be self-hosting.
|
||
|
2) keep a small codebase.
|
||
|
3) remain easy to understand, customize, and fork.
|
||
|
4) never offer more packages than one maintainer can keep up to date.
|
||
|
5) build from sources obtained directly from their authors, whenever possible.
|
||
|
6) support fully open source platforms. (e.g., Talos II.)
|
||
|
|
||
|
## system hygiene
|
||
|
|
||
|
lix helps lix os maintain system hygiene by:
|
||
|
|
||
|
1) building and installing in chroots with only package dependencies available.
|
||
|
2) patching, configuring, and building in an overlay over package source code.
|
||
|
3) mounting an overlay over each chroot before entering the chroot at all.
|
||
|
4) symlinking installed files from package overlays into the filesystem.
|
||
|
|
||
|
all changes during the patching, configuration, building, and installation
|
||
|
phases go into overlays maintained by `lyr`. this helps keep the source code in
|
||
|
`src`'s repository pristine and makes it very simple to activate and deactivate
|
||
|
packages. it also makes it easy to see what packages have supplied each file in
|
||
|
one's system root.
|
||
|
|
||
|
## fork at will
|
||
|
|
||
|
lix os is simple. if one disagrees with a decision, one should fork away. it
|
||
|
should never take more than a single person to maintain a lix os-based
|
||
|
distribution and all its packages.
|
||
|
|
||
|
## _largely_ statically linked
|
||
|
|
||
|
there are some blockers to achieving a fully statically linked system.
|
||
|
|
||
|
### 1) smartcard support
|
||
|
|
||
|
smartcard support is not possible at this time without dynamic linking. in
|
||
|
particular, 'scdaemon' from gnupg loads 'libpcsclite.so' at runtime. there is
|
||
|
not yet a way to make it statically link the library instead. accordingly, the
|
||
|
executables provided by the 'gnupg' package in lix os are linked statically and
|
||
|
do not support smartcards, while the executables in the 'gnupg-dynamic' and
|
||
|
'pcsc-lite' packages are linked dynamically and do support smartcards.
|
||
|
|
||
|
### 2) gui desktops
|
||
|
|
||
|
both x11 and wayland have dependencies which use meson as their build system.
|
||
|
meson requires core python3 modules which use dynamic loading (e.g., ctypes),
|
||
|
which means python3 must be dynamically linked in order to use the meson build
|
||
|
system. the default python3 package is statically linked and does not contain
|
||
|
many "core" modules due to their dependency on the 'dlopen' function. if a gui
|
||
|
is desired, the 'python3-dynamic' package will have to be built.
|
||
|
|
||
|
removing the meson dependency is possible. oasis linux has pioneered this
|
||
|
approach. the best approach would probably be to either port the packaging or
|
||
|
the build system from oasis linux. preferably the latter, since doing so would
|
||
|
better enable collaboration between our projects, but in theory a lua script
|
||
|
could also be written to translate oasis linux packaging into shell scripts
|
||
|
for those unwilling to learn the lua-based build system.
|
||
|
|
||
|
mesa and wayland also tend to not work well when statically linked. in theory
|
||
|
it should be possible to statically link these components, but in practice it
|
||
|
seems to result in segmentation faults. there is probably a way to fix this
|
||
|
problem, but in the meantime a graphical desktop will require dynamic linking.
|
||
|
|
||
|
### 3) gettext
|
||
|
|
||
|
the `kbd` package, which supplies console utilities like `setfont`, requires
|
||
|
`gettext`, and `gettext` will not build statically due to symbol collisions
|
||
|
during while linking. this is also probably fixable, but it would be better to
|
||
|
remove the `gettext` dependency entirely if possible.
|
||
|
|
||
|
## why prefer static linking?
|
||
|
|
||
|
because it should be possible to quantify all of a program's possible states at
|
||
|
compile time, barring hardware-level shenanigans, from source code. a user
|
||
|
should never be put in the position where they are surprised by a change in a
|
||
|
program's behavior because a dynamically loaded library was updated. this seems
|
||
|
analogous to lexical versus dynamic scoping in programming languages.
|
||
|
|
||
|
there are ways to achieve these sorts of guarantees without sacrificing dynamic
|
||
|
loading, but they are more complicated than simply linking statically.
|
||
|
|
||
|
also, no dynamic loader means no dynamic loader vulnerabilities.
|
||
|
|
||
|
## bootstrapping
|
||
|
|
||
|
below is the "official path," but please try other ways and report back.
|
||
|
|
||
|
it is assumed that each step is executed from the same directory. e.g., `~`.
|
||
|
|
||
|
if one prefers to use the linux kernel which contains propietary firmware blobs,
|
||
|
replace references to `linux-libre` below with `linux-kernel`.
|
||
|
|
||
|
01. create an alpine linux installation. leave the target device untouched as
|
||
|
it will need to be formatted and partitioned.
|
||
|
|
||
|
02. install the bootstrap dependencies:
|
||
|
`apk add build-base coreutils cmake git curl rsync cryptsetup autoconf
|
||
|
automake libtool flex bison ncurses-dev`
|
||
|
|
||
|
03. install a command-line text editor and set the EDITOR variable. (optional)
|
||
|
e.g., `apk add vim && export EDITOR='vim'`
|
||
|
(n.b.: if this step is skipped, `vi` will be used.)
|
||
|
(n.b.: in a later step, libraries get moved. if this breaks the text
|
||
|
editor, try another one. if all else fails, `vi` is known to work in alpine
|
||
|
linux and comes installed by default.)
|
||
|
|
||
|
04. clone the lix-os repository and its subrepositories, and install them.
|
||
|
- `git clone http://git.fuwafuwaqtlkkxwc.onion/yafox/lix-os`
|
||
|
- `cd lix-os`
|
||
|
- `make`
|
||
|
- `make install`
|
||
|
|
||
|
05. create a bootstrap layer
|
||
|
- `mkdir bootstrap`
|
||
|
- `./lix-os/utilities/mkbootstrap.sh bootstrap`
|
||
|
|
||
|
06. supply a linux kernel configuration file (strongly recommended but optional)
|
||
|
- `mkdir linux-mnt`
|
||
|
- `lix --bootstrap=bootstrap pull linux-libre`
|
||
|
- `lix --bootstrap=bootstrap mount linux-mnt linux-libre`
|
||
|
- copy the desired kernel configuration file to `linux-mnt/mnt/src/.config`
|
||
|
(n.b.: many distributions have their own kernel configuration files which
|
||
|
can be borrowed. lix os' maintainer keeps a public collection of examples
|
||
|
in the linux-confs repository.)
|
||
|
- `lix umount linux-mnt linux-libre`
|
||
|
- `rmdir linux-mnt`
|
||
|
|
||
|
07. prepare the destination device.
|
||
|
- create an ext4 partition to be used as the boot partition. 100MB should
|
||
|
be plenty of space, assuming no firmware blobs are to be built into the
|
||
|
kernel.
|
||
|
- create a LUKS-encrypted ext4 partition to be used as the root partition.
|
||
|
- create whatever other partitions desired.
|
||
|
|
||
|
08. build lix os
|
||
|
- `"$utilsdir/bootstrap.sh" bootstrap`
|
||
|
(n.b.: some packages will require interactive configuration via text
|
||
|
editor. if a package fails, bootstrapping can be resumed from the same
|
||
|
point later by passing the name of the package as a second argument. e.g.,
|
||
|
`"$utilsdir/bootstrap.sh" bootstrap <failing package>`. this script just
|
||
|
loops over the dependencies of the `lix-os` package, `add`s them, and then
|
||
|
`up`s them in the `lix-os` chroot. it's a short script. don't be afraid
|
||
|
to examine and modify it.)
|
||
|
|
||
|
09. copy lix os to the target medium
|
||
|
- `mkdir -p lix-os-tgt/boot`
|
||
|
- mount the root partition to `lix-os-tgt`
|
||
|
- mount the boot partition to `lix-os-tgt/boot`
|
||
|
- mount any other partitions created earlier under `lix-os-tgt`.
|
||
|
- `"$utilsdir/install.sh" lix-os-tgt`
|
||
|
(n.b.: this script copies the contents of the lix-os chroot and the `src`
|
||
|
and `lyr` repos in /usr/var to the target directory given, then chroots
|
||
|
in to the target directory and replaces all the real files with softlinks
|
||
|
to the appropriate targets in the `lyr` repository via `lix up -f`.)
|
||
|
|
||
|
10. make last-minute configuration changes to boot-related partitions
|
||
|
- edit the contents of `lix-os-tgt/boot/grub/grub.cfg` to point to the
|
||
|
correct partitions.
|
||
|
- make any additional last-minute configuration changes desired.
|
||
|
|
||
|
at this point, if one wishes to skip using symlinks to link installed packages
|
||
|
into the system root instead of having them copied from the package chroots, one
|
||
|
may skip to the last step.
|
||
|
|
||
|
11. unmount boot-related partitions
|
||
|
- `umount lix-os-tgt/boot`
|
||
|
- unmount any additional partitions which should not have their files
|
||
|
converted to symlinks to locations in lyr's layer repository.
|
||
|
(n.b.: this is one of the "sharp edges" of lix os which will one day be
|
||
|
"filed down" in one way or another. in the meantime, take care to not
|
||
|
`lix up` or `lix dn` anything with files related to booting.
|
||
|
`linux-libre`, `lix-os-bootloader`, and `lix-os-initramfs` immediately
|
||
|
come to mind as such packages.)
|
||
|
|
||
|
12. convert everything else to symlinks
|
||
|
- `"$utilsdir/softlink.sh" lix-os-tgt`
|
||
|
|
||
|
13. clean up and reboot into lix os
|
||
|
- unmount the target partitions under and at `lix-os-tgt`.
|
||
|
- `rmdir lix-os-tgt/boot lix-os-tgt`
|
||
|
- reboot into the target medium and make sure lix os works!
|
||
|
|
||
|
## post-bootstrap
|
||
|
|
||
|
if all has gone well and the system is booting, make a backup of your kernel
|
||
|
and initramfs. mount the boot partition and copy `vmlinux` to `vmlinux.bak`
|
||
|
and `initramfs.igz` to `initramfs.igz.bak`. this will allow for recovery by
|
||
|
changing boot parameters to boot with the backup files if one misconfigures
|
||
|
one's kernel or initramfs in the future.
|
||
|
|
||
|
## editing lix-os-initramfs
|
||
|
|
||
|
the contents of the initramfs file can be examined and modified using the
|
||
|
`lix mount` command, the same as every other lix package.
|
||
|
|
||
|
## architecture
|
||
|
|
||
|
lix os tries to be compositional in its architecture, which should make it
|
||
|
easier to replace components as desired. this flexibility comes at the
|
||
|
expense of having all files relevant to a package in a single location. an
|
||
|
earlier iteration of lix os (called 'mu os' in ignorance of the other linux
|
||
|
distribution by that same name) opted for a tighter integration of parts, which
|
||
|
was nice in some ways but which also tended toward creating a monolith.
|
||
|
|
||
|
ideally the lix package manager should be composed of simple tools that behave
|
||
|
in a clear, consistent manner and which have no notions about each other.
|
||
|
|
||
|
## helpful scripts
|
||
|
|
||
|
there are also a number of helpful scripts in the `lix-os-utilities` repository.
|
||
|
for example, the `versions` utility, which itself also depends on `vercmp` and
|
||
|
`shsort`, may be useful for keeping a lix os system up to date. `versions`
|
||
|
returns a sorted list of available package versions pulled directly from each
|
||
|
project maintainer's website and/or its mirrors. lix does not use it directly,
|
||
|
but the author does use it periodically to update `src` packages.
|
||
|
|
||
|
## roadmap
|
||
|
|
||
|
- switch to a "-static-pie" build. (on ppc64le, this currently produces
|
||
|
"read-only segment has dynamic relocations" errors.)
|
||
|
- replace libressl with bearssl.
|
||
|
- replace all gnu tools with simpler alternatives.
|
||
|
[oasis linux](https://github.com/oasislinux/oasis) has the right idea here,
|
||
|
but work needs to be done to add ppc64le support to cproc and the like.
|
||
|
- capture file changes to "upped" packages to their own layer.
|
||
|
- capture file changes to /etc (and others?) to their own layer.
|
||
|
- allow unprivileged creation of user-specific lix environments, like nix os.
|
||
|
- find a way to encourage running processes under least-privileged, package-
|
||
|
specific user accounts whenever possible without literally making the choice
|
||
|
for the user.
|
||
|
- consider separating state in /var into files deterministically generated and
|
||
|
files constituting non-deterministic input. (e.g., 'src' tarballs versus
|
||
|
private keys.)
|
||
|
- consider moving to a model that does require a 'root' user.
|
||
|
- consider merging the overlayfs approach with the autotools-free, lua-as-make
|
||
|
approach of oasis linux.
|
||
|
|
||
|
it would be nice to create something like nix os that captures changed state
|
||
|
rather than requiring state be constructed from a configuration file in a
|
||
|
domain-specific language.
|
||
|
|
||
|
## inspiration
|
||
|
|
||
|
the development of lix os was inspired and aided by the examples set by the
|
||
|
following projects:
|
||
|
|
||
|
- gobo linux and nix os, for sandboxing and separation of state.
|
||
|
- sabotage linux, for general approach and code-centricity.
|
||
|
- kiss linux, for embracing a "remove as many packages as possible" ethos.
|
||
|
- alpine linux, for patches and scripts showing how to build things with musl.
|
||
|
- oasis linux, for helping inform userland choices.
|
||
|
- sta.li, for demonstrating a simplified LHFS.
|
||
|
- openbsd, for providing alternatives such as libressl and doas.
|
||
|
- musl-cross-make, for building a ppc64le-and-musl-targeting c compiler.
|
||
|
- suckless.org, for providing and highlighting simple alternatives, and for
|
||
|
setting me down this path in the first place.
|