
Nooooooooooooooooooooooooooooooooooooooooooooooooooooooo, the doctors have started using AI voice agents and they understand jack shit. ššš
Nooooooooooooooooooooooooooooooooooooooooooooooooooooooo, the doctors have started using AI voice agents and they understand jack shit. ššš
HTTP referrers are quite broken, arenāt they?
Because of that recent storm on my blog, I had a peek at them. Thereās a lot of garbage in there. For example, https://docs.freebsd.org/en/books/handbook/disks-virtual.html is supposed to refer to one of my blog posts ā¦
Whatās going on here?
AI this, AI that.
Tech is no longer interesting. I need to find a new field.
Thinking about doing āWayland Wednesdayā. Only use Wayland every Wednesday. Collect bugs, report bugs, fix bugs.
PSA: setpriv
on Linux supports Landlock.
If this twt goes through, then restricting the filesystem so that jenny can only write to ~/Mail/twt
, ~/www/twtxt.txt
, ~/.jenny-cache
, and /tmp
works.
Something happened with the frame rate of terminal emulators lately. It looks like thereās a trend to run at a high framerate now? Iām not sure exactly. This can be seen in VTE-based terminals like my xiate or XTerm on Wayland. foot and st, on the other hand, are fine.
My shell prompt and cursor look like this:
$ ā
When I keep Enter pressed, I expect to see several lines like so:
$
$
$
$
$
$
$ ā
With the affected terminal emulators, the lines actually show up in the following sequence. First, we have the original line:
$ ā
Pressing Enter yields this as the next frame:
$
ā
And then eventually this:
$
$ ā
In other words, you can see the cursor jumping around very quickly, all the time.
Another example: Vim actually shows which key you just pressed in the bottom right corner. Keeping j
pressed to scroll through a file means I get to see a j
flashing rapidly now.
(I have no idea yet, why exactly XTerm in X11 is fine but flickering in Wayland.)
The WM_CLASS
Property is used on X11 to assign rules to certain windows, e.g. āthis is a GIMP window, it should appear on workspace number 16.ā It consists of two fields, name
and class
.
Wayland (or rather, the XDG shell protocol ā core Wayland knows nothing about this) only has a single field called app_id
.
When you run X11 programs under Wayland, you use XWayland, which is baked into most compositors. Then you have to deal with all three fields.
Some compositors map name
to app_id
, others map class
to app_id
, and even others directly expose the original name
and class
.
Apparently, there is no consensus.
QEMU on Wayland unusable, because it canāt grab the mouse ⦠Iāll add it to my TODO list and investigate/report it eventually.
The lack of suckless-like simple, hackable software these days is appalling.
The Linux installation on my main PC turned 14 today:
$ head -n 1 /var/log/pacman.log
[2011-07-07 11:19] installed filesystem (2011.04-1)
I bought the āremasteredā versions of Grim Fandango and Forsaken on GOG, because theyāre super cheap at the moment. Both have native Linux versions.
And both these Linux version crap their pants. 𫤠The bundled SDL2 of Forsaken says it ācanāt find a matching GLX visualā and I couldnāt figure out how to fix that. I didnāt spend a lot of time on Grim Fandango.
Both work great in Wine. š¤¦
(I do have the original version of Grim Fandango from the 1990ies, but that one does not work so well in Wine. I figured, if itās so cheap, why not. And I now get to play the english version. š The german dub is pretty damn good, actually, but I always prefer the original these days.)
Okay, now this is a very interesting Rust feature:
https://blog.rust-lang.org/2025/07/03/stabilizing-naked-functions/
This (and inline assembly) makes Rust really interesting for very low-level stuff. š„³
It took about a year, I think, but Iāve now finished another run of Tomb Raider I, II, and III. And I have, for the first time, played the two bonus packs āUnfinished Businessā (for TR I) and āGolden Maskā (for TR II). Theyāre available as a free download, if you have the original games. (The bonus pack for TR III is not free.)
I just love these games ā and the game mechanics. Itās just the right balance between challenging and relaxing.
What kind of half-assed nonsense is this? They only broadcast half of the current european soccer cup ⦠(Let me guess, Iām supposed to subscribe to some streaming service if I want to watch every game, right?)
This aggressive auto-logout on my bankās website ā¦
Dude, you want me to print something, sign it, and scan it back in. This takes forever and Iāll have to re-login a dozen times. Narf.
TIL: The logo of sudo
is a sandwich. š« https://www.sudo.ws/
Ted Unangstās snarky (and entertaining) remarks this month:
Someone did a thing:
https://social.treehouse.systems/@ariadne/114763322251054485
Iāve been silently wondering all the time if this was possible, but never investigated: Keep doing X11 but use Wayland as a backend.
This uses XWaylandās ārootfulā mode, which basically just gives you a normal Wayland window with all the X11 stuff happening inside of it:
https://www.phoronix.com/news/XWayland-Rootful-Useful
In other words, put such a window in fullscreen and you (more or less) have good old X11 running in a Wayland window.
(For me, personally, this wonāt be the way forward. But itās a very interesting project.)
Just realized: One of the reasons why I donāt like āflat UIsā is that they look broken to me. Like the program has a bug, missing pixmaps or whatever.
Take this for example:
https://movq.de/v/8822afccf0/a.png
Iām talking about this area specifically:
https://movq.de/v/8822afccf0/a%2Dhigh.png
One UI element ends and the other one begins ā no ātransitionā between them.
The style of old UIs like these two is deeply ingrained into my brain:
https://movq.de/v/8822afccf0/b.png https://movq.de/v/8822afccf0/c.png
When all these little elements (borders, handles, even just simple lines, ā¦) are no longer present, then the program looks buggy and broken to me. And Iām not sure if Iāll ever be able to un-learn that.
Weāre entering the ātoo hot to thinkā-season in 3, 2, 1 ⦠and weāre live!
I did a ālectureā/āworkshopā about this at work today. 16-bit DOS, real mode. š¾ Pretty cool and the audience (devs and sysadmins) seemed quite interested. š„³
The 8086 / 16-bit real-mode DOS is a great platform to explain a lot of the fundamentals without having to deal with OS semantics or executable file formats.
Now that was a lot of fun. š„³ Itās very rare that we do something like this, sadly. I love doing this kind of low-level stuff.
Saw this on Mastodon:
https://racingbunny.com/@mookie/114718466149264471
18 rules of Software Engineering
- You will regret complexity when on-call
- Stop falling in love with your own code
- Everything is a trade-off. There's no "best" 3. Every line of code you write is a liability 4. Document your decisions and designs
- Everyone hates code they didnāt write
- Don't use unnecessary dependencies
- Coding standards prevent arguments
- Write meaningful commit messages
- Don't ever stop learning new things
- Code reviews spread knowledge
- Always build for maintainability
- Ask for help when youāre stuck
- Fix root causes, not symptoms
- Software is never completed
- Estimates are not promises
- Ship early, iterate often
- Keep. It. Simple.
Solid list, even though 14 is up for debate in my opinion: Software can be completed. You have a use case / problem, you solve that problem, done. Your software is completed now. There might still be bugs and they should be fixed ā but this doesnāt āaddā to the program. Donāt use āsoftware is never doneā as an excuse to keep adding and adding stuff to your code.
Okay, hereās a thing I like about Rust: Returning things as Option
and error handling. (Or the more complex Result
, but itās easier to explain with Option
.)
fn mydiv(num: f64, denom: f64) -> Option<f64> {
// (Letās ignore precision issues for a second.)
if denom == 0.0 {
return None;
} else {
return Some(num / denom);
}
}
fn main() {
// Explicit, verbose version:
let num: f64 = 123.0;
let denom: f64 = 456.0;
let wrapped_res = mydiv(num, denom);
if wrapped_res.is_some() {
println!("Unwrapped result: {}", wrapped_res.unwrap());
}
// Shorter version using "if let":
if let Some(res) = mydiv(123.0, 456.0) {
println!("Hereās a result: {}", res);
}
if let Some(res) = mydiv(123.0, 0.0) {
println!("Huh, we divided by zero? This never happens. {}", res);
}
}
You canāt divide by zero, so the function returns an āerrorā in that case. (Option
isnāt really used for errors, IIUC, but the basic idea is the same for Result
.)
Option
is an enum. It can have the value Some
or None
. In the case of Some
, you can attach additional data to the enum. In this case, we are attaching a floating point value.
The caller then has to decide: Is the value None
or Some
? Did the function succeed or not? If it is Some
, the caller can do .unwrap()
on this enum to get the inner value (the floating point value). If you do .unwrap()
on a None
value, the program will panic and die.
The if let
version using destructuring is much shorter and, once you got used to it, actually quite nice.
Now the trick is that you must somehow handle these two cases. You must either call something like .unwrap()
or do destructuring or something, otherwise you canāt access the attached value at all. As I understand it, it is impossible to just completely ignore error cases. And the compiler enforces it.
(In case of Result
, the compiler would warn you if you ignore the return value entirely. So something like doing write()
and then ignoring the return value would be caught as well.)
We really are bouncing back and forth between flat UIs and beveled UIs. I mean, this is what old X11 programs looked like:
https://www.uninformativ.de/desktop/2025%2D06%2D21%2D%2Dkatriawm%2Dold%2Dxorg%2Dapps.png
Good luck figuring out which of these UI elements are click-able ā unless you examine every pixel on the screen.
Speaking of Wine, Arch Linux completely fucked up Wine for me with the latest update.
Arch is shipping a WoW64 build now, which is not yet ready for prime time.
And then I realized that thereās actually only one stable Wine release per year but Arch has been shipping development releases all the time. Thatās quite unusual. Iām used to Arch only shipping stable packages ⦠huh.
Hopefully things will improve again. Iām not eager to build Wine from source. Iād rather ditch it and resort to my real Windows XP box for the little (retro)gaming that I do ⦠š«¤
To really annoy my neighbors and everyone in a 5 mile radius, I might take my Model M and type a blogpost on the balcony. š
Fuck me sideways, Rust is so hard. Will we ever be friends?
OpenBSD has the wonderful pledge()
and unveil()
syscalls:
https://www.youtube.com/watch?v=bXO6nelFt-E
Not only are they super useful (the program itself can drop privileges ā like, it can initialize itself, read some files, whatever, and then tell the kernel that it will never do anything like that again; if it does, e.g. by being exploited through a bug, it gets killed by the kernel), but they are also extremely easy to use.
Imagine a server program with a connected socket in file descriptor 0. Before reading any data from the client, the program can do this:
unveil("/var/www/whatever", "r");
unveil(NULL, NULL);
pledge("stdio rpath", NULL);
Done. Itās now limited to reading files from that directory, communicating with the existing socket, stuff like that. But it cannot ever read any other files or exec()
into something else.
I canāt wait for the day when we have something like this on Linux. There have been some attempts, but itās not that easy. And itās certainly not mainstream, yet.
I need to have a closer look at Linuxās Landlock soon (āsoonā), but this is considerably more complicated than pledge()
/unveil()
:
āLearn Something Old Every Day, Part XV: KEYB Is Half of Keyboard BIOSā
https://www.os2museum.com/wp/learn-something-old-every-day-part-xv-keyb-is-half-of-keyboard-bios/
fn sub(foo: &String) {
println!("We got this string: [{}]", foo);
}
fn main() {
// "Hello", 0x00, 0x00, "!"
let buf: [u8; 8] = [0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x00, 0x00, 0x21];
// Create a string from the byte array above, interpret as UTF-8, ignore decoding errors.
let lossy_unicode = String::from_utf8_lossy(&buf).to_string();
sub(&lossy_unicode);
}
Create a string from a byte array, but the result isnāt a string, itās a cow š®, so you need another to_string()
to convert your āstringā into a string.
I still have a lot to learn.
(into_owned()
instead of to_string()
also works and makes more sense to me, itās just that the compiler suggested to_string()
first, which led to this funny example.)
So I was using this function in Rust:
https://doc.rust-lang.org/std/path/struct.Path.html#method.display
Note the little 1.0.0
in the top right corner, which means that this function has been āstable since Rust version 1.0.0ā. Weāre at 1.87 now, so weāre good.
Then I compiled my program on OpenBSD with Rust 1.86, i.e. just one version behind, but well ahead of 1.0.0.
The compiler said that I was using an unstable library feature.
Turns out, that function internally uses this:
https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.display
And that is only available since Rust 1.87.
How was I supposed to know this? š¤Øš«©
Gopher server is back online and Iāll be phasing out Mastodon.
gopher://uninformativ.de
(No, I wonāt do multi-protocol twtxt again. š )
Sitting on the balcony with a fucking cup of coffee. https://movq.de/v/463f1f9d03/s.png
Bird photos of the day:
Having some fun with SIRDS this morning.
What you should see: https://movq.de/v/dae785e733/disp.png
And the tutorial I used for my C program: https://www.ime.usp.br/~otuyama/stereogram/basic/index.html
A bill from our ISP in 1998.
Weāre talking about a month here, 1998-07-27 to 1998-08-26.
Basic fee: 7.50 DM (about 6⬠today).
Online time: 516 minutes, 23.53 DM (about 20⬠today).
Thatās just the ISP costs, if Iām not mistaken. The underlying phone calls were pretty pricey as well.
When I chose the MIT license for all of my software, I thought:
āShould I use GPL, which I donāt really understand? Is that worth it? Yeah, there is a theoretical possibility that some company might use my code in their proprietary product ⦠and then what? Should I sue them to enforce the GPL? Iām not going to do that anyway, so Iāll just use the MIT license.ā
And now we have those LLM scrapers and now itās suddenly a reality that these companies (ab)use my code. I can see it in my logs. I didnāt expect that back then.
GPL wouldnāt help, either, of course. (Regardless, I now think that GPL would have been the better choice anyway.)
Iām honestly considering taking my code and website offline. Maybe make it accessible through some obscure protocol like Gopher or Gemini, but no more HTTP.
(Yes, Anubis might help. Temporarily.)
Iām just tired.
I had a lot of fun with my modems these past few days:
https://www.uninformativ.de/blog/postings/2025-05-31/0/POSTING-en.html
My website is compatible with many old browsers, but Internet Explorer 3, uhm, not so much.
Maybe youāll enjoy this as well:
I still have one of my first modems, a Creatix LC 144 VF:
I think this was the modem that I used when I first connected to the internet, but Iām not sure.
I plugged it in again and it still works:
The firmware appears to be from 1994, which sounds about right. I donāt think we had internet access before that. We certainly did use local mailboxes, though. (Or BBSās, as you might call them.)
I now want to actually use that modem again. For the moment, I can only use a phone to dial into it, I lack a second modem to actually establish a connection. Hereās a video:
Not spectacular, but the modem does answer after me entering ATA
.
I bought another cheap old modem on eBay and am now waiting for it to arrive. Once itās here, I want to simulate an actual dial-up session, hopefully from OS/2 or Windows 3.x.
That was so great to watch, I was smiling from ear to ear the whole time. š
Happy to report that the neighbor has started playing Tschaikowski on their piano. And theyāre getting really good at it! This is awesome. š
Wanna read something very scary?
Your future doctor is using ChatGPT to pass medical school, so you better start riding a bike and eating healthy now.
šØšØšØ
Zum Entsetzen aller Beteiligten, wie auch umstehender Personen und einiger schamfreier Gaffer, welche sich an jenem tosenden Unheil zu ergƶtzen vermochten, folgte nun des Wochensortiments schrecklichste GeiĆel: šÆšš šøššššš.
Und es sollten sich die Wolken teilen, um über ihnen nimmer endende Irrungen und Wirrungen an bovinem FƤkal und fremdgetriebener Lethargie zu erbrechen, auf dass sie zu erkennen gezwungen wƤren, welche Urkraft der irrealen Zusammenkunft letztlich Herrschaft über sie darstellen sollte: šÆšš ššššššššššš.
So zogen sie alsbald hin, zu tun wie ihnen geheiĆen, wohlgleich sie ā diesem Schauerspiel trotzend ā Trost suchten im einzigen ihnen sicher geglaubten Elixir, das dem Abgrund unter ihnen gleichend tiefschwarz glitzernd Erlƶsung oder mithin als MindestmaĆ Linderung versprach, lag jenes doch in unmittelbarer NƤhe befindlich hoffnungsschürend bereit:
KĢøĶĶĶĶĶ̄ä̷ĢĶ̯̼̤Ķf̵̿ĢĶĢ̧f̷̾ĶĢ«ĢĢcĢøĢĢĶh̶ĢĶĶĶ̳eĢ·ĶĶĶĢ«ĢĶn̵Ģ̨̳̬?Ģ“ĶĢĢ© ā