PatOS is born!

This commit is contained in:
Lars Sjöström 2024-09-12 21:57:01 +02:00
parent 0f3b2072f4
commit 44d8f9c90d
No known key found for this signature in database
12 changed files with 383 additions and 0 deletions

1
.envrc Normal file
View file

@ -0,0 +1 @@
use flake

6
.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
.env
.direnv
.task
result
.*.swp
.*.swo

11
base.nix Normal file
View file

@ -0,0 +1,11 @@
{ ... }: {
imports = [
./modules/system_overrides.nix
./modules/minimize.nix
./modules/generic.nix
./modules/filesystems.nix
./modules/partitions.nix
./modules/network.nix
./modules/sysupdate.nix
];
}

27
flake.lock Normal file
View file

@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1725983898,
"narHash": "sha256-4b3A9zPpxAxLnkF9MawJNHDtOOl6ruL0r6Og1TEDGCE=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "1355a0cbfeac61d785b7183c0caaec1f97361b43",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

70
flake.nix Normal file
View file

@ -0,0 +1,70 @@
{
description = "PatOS is a minimal, immutable Linux distribution specialized for the Patagia Platform.";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
};
outputs = { self, nixpkgs }: {
lib = {
# Prepare a ready-to-boot disk image.
mkInstallImage = nixos:
let
config = nixos.config;
pkgs = nixpkgs.legacyPackages.x86_64-linux.pkgs;
in
nixos.pkgs.runCommand "update-${config.system.image.version}"
{
nativeBuildInputs = with pkgs; [ qemu ];
} ''
mkdir -p $out
qemu-img convert -f raw -O qcow2 -C ${config.system.build.image}/${config.boot.uki.name}_${config.system.image.version}.raw $out/disk.qcow2
'';
};
devShells.x86_64-linux.default =
let
pkgs = nixpkgs.legacyPackages.x86_64-linux;
in
pkgs.mkShell {
packages = [
self.packages.x86_64-linux.qemu-efi
];
};
packages.x86_64-linux = {
default = self.packages.x86_64-linux.patos_image;
patos_image = self.lib.mkInstallImage self.nixosConfigurations.patos;
# A helper script to run the disk images above.
qemu-efi =
let
pkgs = nixpkgs.legacyPackages.x86_64-linux;
in
pkgs.writeShellApplication {
name = "qemu-efi";
runtimeInputs = [ pkgs.qemu_kvm ];
text = ''
qemu-system-x86_64 \
-smp 2 -m 2048 -machine q35,accel=kvm \
-bios ${pkgs.OVMF.fd}/FV/OVMF.fd \
-snapshot \
-display none \
-serial stdio "$@"
'';
};
};
nixosConfigurations = {
patos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./base.nix
];
};
};
};
}

44
modules/filesystems.nix Normal file
View file

@ -0,0 +1,44 @@
{ config, ... }: {
zramSwap = {
enable = true;
algorithm = "zstd";
memoryPercent = 20;
};
fileSystems = {
"/" = {
fsType = "tmpfs";
options = [
"size=20%"
];
};
"/var" =
let
partConf = config.image.repart.partitions."var".repartConfig;
in
{
device = "/dev/disk/by-partuuid/${partConf.UUID}";
fsType = partConf.Format;
};
"/boot" =
let
partConf = config.image.repart.partitions."esp".repartConfig;
in
{
device = "/dev/disk/by-partuuid/${partConf.UUID}";
fsType = partConf.Format;
};
"/nix/store" =
let
partConf = config.image.repart.partitions."store".repartConfig;
in
{
device = "/dev/disk/by-partlabel/${partConf.Label}";
fsType = partConf.Format;
};
};
}

41
modules/generic.nix Normal file
View file

@ -0,0 +1,41 @@
{ pkgs, config, ... }: {
boot.uki.name = "patos";
boot.kernelParams = [ "console=ttyS0" ];
system.nixos.release = "2024-09";
system.nixos.codeName = "Finn";
system.nixos.distroId = "patos";
system.nixos.distroName = "PatOS";
system.image.version = "0.0.1"; # FIXME: Use epoch version.
# Make the current system version visible in the prompt.
programs.bash.promptInit = ''
export PS1="\u@\h (version ${config.system.image.version}) $ "
'';
# Not compatible with system.etc.overlay.enable yet.
# users.mutableUsers = false;
services.getty.autologinUser = "root";
boot.initrd.systemd.enable = true;
# Don't accumulate crap.
boot.tmp.cleanOnBoot = true;
services.journald.extraConfig = ''
SystemMaxUse=10M
'';
# Debugging
environment.systemPackages = with pkgs; [
parted
(runCommand "systemd-sysupdate" { } ''
mkdir -p $out/bin
ln -s ${config.systemd.package}/lib/systemd/systemd-sysupdate $out/bin
'')
];
system.stateVersion = "24.11";
}

19
modules/minimize.nix Normal file
View file

@ -0,0 +1,19 @@
{ modulesPath, ... }: {
imports = [
"${modulesPath}/profiles/minimal.nix"
];
boot.loader.grub.enable = false;
system.switch.enable = false;
nix.enable = false;
system.etc.overlay.enable = true;
systemd.sysusers.enable = true;
system.disableInstallerTools = true;
programs.less.lessopen = null;
programs.command-not-found.enable = false;
boot.enableContainers = false;
environment.defaultPackages = [ ];
}

11
modules/network.nix Normal file
View file

@ -0,0 +1,11 @@
{ config, ... }: {
networking = {
useNetworkd = true;
# Easy debugging.
firewall.enable = false;
};
# Faster boot.
systemd.network.wait-online.enable = false;
}

85
modules/partitions.nix Normal file
View file

@ -0,0 +1,85 @@
{ config, pkgs, lib, modulesPath, ... }: {
imports = [
"${modulesPath}/image/repart.nix"
];
image.repart =
let
efiArch = pkgs.stdenv.hostPlatform.efiArch;
in
{
name = config.boot.uki.name;
split = true;
partitions = {
"esp" = {
contents = {
"/EFI/BOOT/BOOT${lib.toUpper efiArch}.EFI".source =
"${pkgs.systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi";
"/EFI/Linux/${config.system.boot.loader.ukiFile}".source =
"${config.system.build.uki}/${config.system.boot.loader.ukiFile}";
# systemd-boot configuration
"/loader/loader.conf".source = (pkgs.writeText "$out" ''
timeout 3
'');
};
repartConfig = {
Type = "esp";
UUID = "c12a7328-f81f-11d2-ba4b-00a0c93ec93b"; # Well known
Format = "vfat";
SizeMinBytes = "256M";
SplitName = "-";
};
};
"store" = {
storePaths = [ config.system.build.toplevel ];
stripNixStorePrefix = true;
repartConfig = {
Type = "linux-generic";
Label = "store_${config.system.image.version}";
Format = "squashfs";
Minimize = "off";
ReadOnly = "yes";
SizeMinBytes = "1G";
SizeMaxBytes = "1G";
SplitName = "store";
};
};
# Placeholder for the second installed Nix store.
"store-empty" = {
repartConfig = {
Type = "linux-generic";
Label = "_empty";
Minimize = "off";
SizeMinBytes = "1G";
SizeMaxBytes = "1G";
SplitName = "-";
};
};
# Persistent storage
"var" = {
repartConfig = {
Type = "var";
UUID = "4d21b016-b534-45c2-a9fb-5c16e091fd2d"; # Well known
Format = "xfs";
Label = "nixos-persistent";
Minimize = "off";
# Has to be large enough to hold update files.
SizeMinBytes = "2G";
SizeMaxBytes = "2G";
SplitName = "-";
# Wiping this gives us a clean state.
FactoryReset = "yes";
};
};
};
};
}

View file

@ -0,0 +1,5 @@
{ lib, options, ... }: {
# This fields is immutable by default, but can be overridden.
options.system.nixos.codeName = lib.mkOption { readOnly = false; };
options.system.nixos.release = lib.mkOption { readOnly = false; };
}

63
modules/sysupdate.nix Normal file
View file

@ -0,0 +1,63 @@
{ config, ... }: {
systemd.sysupdate = {
enable = true;
transfers = {
"10-uki" = {
Source = {
MatchPattern = [
"${config.boot.uki.name}_@v.efi.xz"
];
# We could fetch updates from the network as well:
#
# Path = "https://download.example.com/";
# Type = "url-file";
Path = "/var/updates/";
Type = "regular-file";
};
Target = {
InstancesMax = 2;
MatchPattern = [
"${config.boot.uki.name}_@v.efi"
];
Mode = "0444";
Path = "/EFI/Linux";
PathRelativeTo = "boot";
Type = "regular-file";
};
Transfer = {
ProtectVersion = "%A";
};
};
"20-store" = {
Source = {
MatchPattern = [
"store_@v.img.xz"
];
# Path = "https://download.example.com/";
# Type = "url-file";
Path = "/var/updates/";
Type = "regular-file";
};
Target = {
InstancesMax = 2;
# This doesn't work, because / is a tmpfs and the heuristic is not that smart.
#
# Path = "auto";
Path = "/dev/sda";
MatchPattern = "store_@v";
Type = "partition";
ReadOnly = "yes";
};
};
};
};
}