Continuing yesterday's thread: we left off with dinit launching, but /etc being messed up.
I fixed /etc! The trick ended up mounting shit on top of each other after chrooting.
Next step: make the netbsd core stuff read-only.
Discussion
Continuing yesterday's thread: we left off with dinit launching, but /etc being messed up.
I fixed /etc! The trick ended up mounting shit on top of each other after chrooting.
Next step: make the netbsd core stuff read-only.
Also, I will slowly start publishing my current experiments. I'll call the repo fuck/fuckery.
Soo... I currently have:
/etc layered on top of NetBSD's etcdinit booting into a system that has getty on constty for root loginI basically have all the tools to make a bootable system that then I can use to develop itself. It's not there yet, because at a minimum, I need a network, and either ssh or git. Since ssh is in the NetBSD base, that's a whole lot easier.
With ssh, I can TRAMP into the system and edit the code. I can't commit locally, but I can edit things remotely, and that's good enough.
...except I don't have a user yet. Oops.
Next steps are:
/var from persistence, union mounted over NetBSD's /vargitI (well, @doctor) was also thinking about packaging and bootstrapping last night, and I think we have arrived to a plan that could make the whole distribution building a little easier!
I'll have a few special builders!
A builder for NetBSD sets: you give it a NetBSD version, a list of sets, and it downloads the binaries, and extracts them. The hash will be the NetBSD version + setlist + arch.
A builder for pkgsrc: give it a pkgsrc, $category/$program, and it builds that. Hash will be the hash of all files in the given package's pkgsrc dir.
The pkgsrc builds will not be reproducable, as they will depend on local state. They're a hack to let me bootstrap the rest of the system more easily.
This is more complicated than anticipated! Setting up the network is non-trivial work.
I might cheat there a bit.
Lets go with even smaller steps... first: adjust dinit to take care of mounting the necessary kernel filesystems like /proc, /kern, etc.
Done!
Now we'll do a bit of cheating.
Oh. I need to do the /var mounting sooner, because dhcpcd requires that.
Hrm. /etc/rc.d/dhcpcd onestart runs, but doesn't get an IP.
Aand I have network!
Uhhuh. Hm. Users will be a bit of a bother in the longer run, because the passwords are in a binary thingamajiggy. But for now, I'll shove it onto persistence.
Haha. Funny. I have no $HOME and I want to scream.
In the long run, $HOME will be tmpfs too - but not today yet.
$HOME sweet $HOME.
❯ ssh carrot -- pwd
/sexshop/bdsm/homes/algernon
I could null-mount it, so it would appear as /home/algernon, but... I like it this way.
Now to set -o hidden for most of the null mounts, because...
❯ ssh carrot -- df -h
Filesystem Size Used Avail %Cap Mounted on
tmpfs 4.0M 12K 4.0M 1% /
/dev/dk0 9.7G 1.0G 8.2G 11% /sexshop/bondage
/dev/dk2 39G 28M 37G 1% /sexshop/toys
/dev/dk3 39G 3.3M 37G 1% /sexshop/bdsm
/sexshop/bondage/dev 9.7G 1.0G 8.2G 11% /dev
/sexshop/bondage/bin 9.7G 1.0G 8.2G 11% /bin
/sexshop/bondage/sbin 9.7G 1.0G 8.2G 11% /sbin
/sexshop/bondage/lib 9.7G 1.0G 8.2G 11% /lib
/sexshop/bondage/libdata 9.7G 1.0G 8.2G 11% /libdata
/sexshop/bondage/libexec 9.7G 1.0G 8.2G 11% /libexec
/sexshop/bondage/usr/bin 9.7G 1.0G 8.2G 11% /usr/bin
/sexshop/bondage/usr/sbin 9.7G 1.0G 8.2G 11% /usr/sbin
/sexshop/bondage/usr/include 9.7G 1.0G 8.2G 11% /usr/include
/sexshop/bondage/usr/lib 9.7G 1.0G 8.2G 11% /usr/lib
/sexshop/bondage/usr/libdata 9.7G 1.0G 8.2G 11% /usr/libdata
/sexshop/bondage/usr/libexec 9.7G 1.0G 8.2G 11% /usr/libexec
/sexshop/bondage/usr/mdec 9.7G 1.0G 8.2G 11% /usr/mdec
/sexshop/bondage/usr/share 9.7G 1.0G 8.2G 11% /usr/share
/sexshop/bondage/rescue 9.7G 1.0G 8.2G 11% /rescue
<above>:/sexshop/bdsm/system/etc 40G 1.0G 37G 3% /sexshop/bondage/etc
tmpfs 4.0G 0B 4.0G 0% /tmp
kernfs 1.0K 1.0K 0B 100% /kern
procfs 4.0K 4.0K 0B 100% /proc
ptyfs 1.0K 1.0K 0B 100% /dev/pts
<above>:/sexshop/bdsm/system/var 40G 1.0G 37G 3% /sexshop/bondage/var
This is very silly.
❯ ssh carrot -- df -h
Filesystem Size Used Avail %Cap Mounted on
tmpfs 4.0M 12K 4.0M 1% /
/dev/dk0 9.7G 1.0G 8.2G 11% /sexshop/bondage
/dev/dk2 39G 28M 37G 1% /sexshop/toys
/dev/dk3 39G 3.3M 37G 1% /sexshop/bdsm
procfs 4.0K 4.0K 0B 100% /proc
tmpfs 4.0G 0B 4.0G 0% /tmp
ptyfs 1.0K 1.0K 0B 100% /dev/pts
kernfs 1.0K 1.0K 0B 100% /kern
/dev/dk4 93G 14G 74G 17% /legacy
Much better.
Next thing to fix: rebooting. Need to do the filesystem unmount dance there.
Would also need to fsck the filesystems too...
I'll also need to teach my initrd init to mount filesystems by ID, rather than /dk$N, because /dk$N is discovery ordered, and can vary between reboots.
Aha! getfsspecname(3)!
That was reasonably easy.
Ergh. Will also need a pkgin-binary builder too, for the cases where I don't want to build from pkgsrc, as a shortcut.
(This toot sponsored by sh: git: not found, and other dependencies.)
Next steps:
/etc/dinit.d under version controlgit to the storefsck all the thingsAnd then I have a system that I can use to develop itself. Well, technically, I can do that without the last step.
Oh dear. I have Ideas™. Package management ideas.
Just spitballing here...
node carota-sativa {
operating-system netbsd
disk "/dev/ld0" partition=gpt {
// some disk partitioning stuff here
}
hostname "carota-sativa.madhouse.local"
network vioif0 { dhcp; }
service ssh {
enable
config PermitRootLogin yes
}
user algernon {
name "Gergely Nagy"
password file=${secrets.user.algernon.password}
shell package=tbd // to be decided!
}
}
Not fully fleshed out, of course. Just... spitballing here.
"But algernon, you promised us a Lisp!", I hear you all yelling.
But here's the thing I realized while I was going over a gazillion variations of configuration: one of the things I dislike about both Nix and Guix is that the configuration language and the extension language are the same.
I do not want my configuration to be a programming language. Yes, that makes some crazy stuff possible, but it also means I have to learn that language, and all its edge cases and whatnot. In case of Nix, that's a truly horrible, cursed language. In case of Guile - that's a great language! But... I still don't want to write a program as my configuration. I want it to be a document.
So I'll make it a document. A KCuddly Document Language.
But here's a twist... hold on to your pants.
Here's how the same document looks, when it only contains nodes implemented by fuck (the package manager) itself:
// ...crickets...
You see, I'm might have fallen into this trap of "lets write a runtime, embed some language, let that do the hard stuff!". I did that with iocaine, I'm doing it with ryoms, and I'm doing it with fuck too.
The idea is that fuck sets up a runtime, with a couple of helper functions, but pretty much not much else. It will delegate that to the embedded scripting language.
Now that can be a real programming language! Because it's not dealing with configuration! It's implementing a configuration system! It's meant to be a program!
And I like this separation.
What the embedded language will be? I don't know yet. I know what it won't be (Roto).
It could be a Lisp, it coulbe Guile, it could be scheme-rs, it could be Steel, it could be Fennel (on top of Lua). It could be something else.
...or it could be all of them. Because all it does is take a bit of KDL configuration, and spew out something fuck can work with1. When fuck encounters a node in the KDL it can't handle, it'll check whether any of the runtimes implement it. As in, it will pass the node through all of them, until one resolves it. The runtimes get the node, the rest of the configuration, and the current state of things.
So you can implement part of the system in Guile, another part in Fennel, some in Rhai, or what have you. If it can speak KDL, and fuck's state, I want you to be able to plug it in.
What that is? I don't know yet. ↩︎
But wait, there's more! I have Ideas™ not only about syntax, but also about systems. As in, while I've been thinking about the configuration format, another conclusion I came to is that I do not like lock files, and I will not have them, if I can avoid it.
Imagine this:
input iocaine {
source {
fetcher forgejo
forge "https://git.madhouse-project.org"
repository "iocaine/iocaine.git"
commit "81478c9a762b0272de74d39f8764f8e912e68fc0"
update-from branch=iocaine-3.x
}
}
So, here, the input is directly in the configuration, specified exactly. In this case, there's no hash needed, the commit ID is good enough. But the upgrade path is also there, and fully supported by fuck: fuck input update iocaine goes out, checks the latest commit on the iocaine-3.x branch, and tells you. Perhaps even provides a diff, if I can make that work.
Want to package something, without an external input?
package iocaine {
source {
// same thing as in last toot
}
builder cargo
}
And there's plenty more! All of it very... in flux. I will likely iterate over the syntax and features quite a lot. And that's another reason why N+1 runtimes help: it also makes experimenting a whole lot easier. I can keep fuck as-is, write another node interpreter in whatever language I want, plug it in, see how it feels, even verify that it yields the same output as the previous iteration.
@algernon wait, while I looked away for a day or three you started building a declarative package manager (+maybe distro?) on netbsd?
Wow (positive)
re: mouse makes rocks do math (fuckboi edition)
@algernon
multi layer mounting