<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><id>https://blog.goeswhere.com</id><title>Faux' Blog</title><updated>2026-02-22T14:51:49.609755+00:00</updated><author><name>Chris West (Faux)</name></author><link href="https://blog.goeswhere.com" rel="alternate"/><generator uri="https://lkiesow.github.io/python-feedgen" version="1.0.0">python-feedgen</generator><subtitle>Faux' (mostly) technical blog</subtitle><entry><id>https://blog.goeswhere.com/2017/02/seccomp-tool/</id><title>Playing with prctl and seccomp</title><updated>2026-02-22T14:30:08.344927+00:00</updated><content>&lt;p&gt;I have been playing with low-level Linux security features, such as
&lt;a href="https://www.kernel.org/doc/Documentation/prctl/no_new_privs.txt"&gt;prctl no new privs&lt;/a&gt;
and &lt;a href="https://www.kernel.org/doc/Documentation/prctl/seccomp_filter.txt"&gt;seccomp&lt;/a&gt;.
These tools allow you to reduce the harm a process can do to your system.&lt;/p&gt;
&lt;p&gt;They're typically deployed as part of systemd, although the &lt;a href="https://lwn.net/Articles/709755/"&gt;default settings in
many distros are yet to be ideal&lt;/a&gt;. This is partly
because it's hard to confirm what a service actually needs, and partly because many services
&lt;em&gt;support&lt;/em&gt; many more things than a typical user cares about.&lt;/p&gt;
&lt;p&gt;For example, should a web server be able to make &lt;em&gt;outgoing&lt;/em&gt; network connections?
Probably not, it's accepting network connections from people, maybe running some code,
then returning the response. However, maybe you're hosting some PHP that you want to be
able to fetch data from the internet? Maybe you're running your web-server as a proxy?&lt;/p&gt;
&lt;p&gt;To address these questions, Debian/Ubuntu typically err on the side of "let it do whatever,
so users aren't inconvenienced". CentOS/RHEL have started adding a large
&lt;a href="https://wiki.centos.org/TipsAndTricks/SelinuxBooleans"&gt;selection of flags you can toggle&lt;/a&gt;
to fiddle security (although through yet another mechanism, not the one we're talking about here..).&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Anyway, let's assume you're paranoid, and want to increase the security of your services.
The two features discussed here are exposed in systemd as
&lt;a href="https://www.freedesktop.org/software/systemd/man/systemd.exec.html#NoNewPrivileges="&gt;NoNewPrivileges=&lt;/a&gt;
and
&lt;a href="https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter="&gt;SystemCallFilter=&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The first, &lt;code&gt;NoNewPrivileges=&lt;/code&gt;, prevents a process from getting privileges in any common way,
e.g. by trying to change user, or trying to run a command which has privileges (e.g. capabilities)
attached.&lt;/p&gt;
&lt;p&gt;This is great. Even if someone knows your root password, they're still stuck:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;% systemd-run --user -p NoNewPrivileges=yes --tty -- bash
$ su - root
Password:
su: Authentication failure

$ sudo ls
sudo: effective uid is not 0, is /usr/bin/sudo on a file system with the 'nosuid'
  option set or an NFS file system without root privileges?
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The errors aren't great, as the tools have no idea what's going on, but at least it works!&lt;/p&gt;
&lt;p&gt;This seems like a big, easy win; I don't need my &lt;code&gt;php&lt;/code&gt; application to become a different
user... or do I? It turns out that the venerable &lt;code&gt;mail&lt;/code&gt; command, on a &lt;code&gt;postfix&lt;/code&gt; system,
eventually tries to run a setuid binary, which fails. And &lt;code&gt;php&lt;/code&gt; defaults to sending mail
via. this route. Damn!&lt;/p&gt;
&lt;p&gt;Let's try it out:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;% systemd-run --user -p NoNewPrivileges=yes --tty -- bash
faux@astoria:~$ echo hi | mail someone@example.com
faux@astoria:~$

postdrop: warning: mail_queue_enter: create file maildrop/647297.680: Permission denied
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yep, &lt;code&gt;postdrop&lt;/code&gt; is setgid (the weird &lt;code&gt;s&lt;/code&gt; in the permissions string):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;% ls -al =postdrop
-r-xr-sr-x 1 root postdrop 14328 Jul 29  2016 /usr/sbin/postdrop
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It turns out that
&lt;a href="https://lists.freedesktop.org/archives/systemd-devel/2014-June/020212.html"&gt;Debian dropped support for alternative ways to deliver mail&lt;/a&gt;. So, we can't use that!&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Earlier I implied that &lt;code&gt;NoNewPrivileges=&lt;/code&gt;, despite the documentation, doesn't
remove all ways to get some privileges. One way to do this is to enter a new
user namespace (only widely supported by Ubuntu as of today). e.g. we can get
&lt;a href="https://people.canonical.com/~ubuntu-security/cve/2016/CVE-2016-8655.html"&gt;&lt;code&gt;CAP_NET_RAW&lt;/code&gt; (and its associated vulnerabilities)&lt;/a&gt;
through user namespaces:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;% systemd-run --user -p NoNewPrivileges=yes --tty -- \
    unshare --map-root-user --net -- \
    capsh --print \
        | fgrep Current: | egrep -o 'cap_net\w+'
cap_net_bind_service
cap_net_broadcast
cap_net_admin
cap_net_raw
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To harden against this, I wrote
&lt;a href="https://github.com/FauxFaux/tinies/blob/master/drop-privs-harder.c"&gt;drop-privs-harder&lt;/a&gt;
which simply breaks &lt;code&gt;unshare&lt;/code&gt; (and its friend &lt;code&gt;clone&lt;/code&gt;)'s ability to make new user
namespaces, using &lt;code&gt;seccomp&lt;/code&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Unlike &lt;code&gt;NoNewPrivileges=&lt;/code&gt;, &lt;code&gt;SystemCallFilter=&lt;/code&gt; takes many more arguments, and
requires significantly more research to work out whether a process is going to work.
Additionally, &lt;code&gt;systemd-run&lt;/code&gt; doesn't support &lt;code&gt;SystemCallFilter=&lt;/code&gt;. I'm not sure why.&lt;/p&gt;
&lt;p&gt;To assist people playing around with this (on amd64 only!), I wrote a tool named
&lt;a href="https://github.com/FauxFaux/tinies/blob/master/seccomp-tool.c"&gt;seccomp-tool&lt;/a&gt;
and a front-end named
&lt;a href="https://github.com/FauxFaux/tinies/blob/master/seccomp-filter.py"&gt;seccomp-filter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There's a &lt;a href="/files/seccomp-tool-v0.0.1"&gt;binary of &lt;code&gt;seccomp-tool&lt;/code&gt;&lt;/a&gt;
available for anyone who doesn't feel like compiling it. It depends on only
&lt;code&gt;libseccomp2&lt;/code&gt;. &lt;code&gt;sudo apt install libseccomp2&lt;/code&gt;. It needs to be in your path as &lt;code&gt;seccomp-tool&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;seccomp-filter&lt;/code&gt; supports the
&lt;a href="https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter="&gt;predefined system call sets&lt;/a&gt;
from the systemd documentation, in addition to an extra set, named &lt;code&gt;@critical&lt;/code&gt;,
which systemd seems to silently include without telling you. Both of these tools
set &lt;code&gt;NoNewPrivilges=&lt;/code&gt;, so you will also be testing that.&lt;/p&gt;
&lt;p&gt;Let's have a play:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;% seccomp-filter.py @critical -- ls /
ls: reading directory '/': Function not implemented
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we're trying to run &lt;code&gt;ls&lt;/code&gt; with only the absolutely critical syscalls enabled.
&lt;code&gt;ls&lt;/code&gt;, after starting, tries to call &lt;code&gt;getdents()&lt;/code&gt; ("list the directory"), and gets
told that it's not supported. Returning &lt;code&gt;ENOSYS&lt;/code&gt; ("function not implemented") is
the default behaviour for &lt;code&gt;seccomp-filter.py&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can have a permissions error, instead, if we like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;% seccomp-filter.py --exit-code EPERM @critical -- ls /
ls: reading directory '/': Operation not permitted
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we give it &lt;code&gt;getdents&lt;/code&gt;, it starts working... almost:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;% ./seccomp-filter.py --exit-code EPERM @critical getdents -- ls /proc
1
10
1001
11
1112
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Why does the output look like it's been piped through a pager? &lt;code&gt;ls&lt;/code&gt; has tried
to talk to the terminal, has been told it can't, and is okay with that.
This looks the same as:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;seccomp-filter.py --blacklist ioctl -- ls /
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we add &lt;code&gt;ioctl&lt;/code&gt; to the list again, &lt;code&gt;ls&lt;/code&gt; pretty much works as expected,
ignoring the fact that it segfaults during shutdown. systemd's &lt;code&gt;@default&lt;/code&gt;
group of syscalls is useful to include to remove this behaviour.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next, I looked at what Java required. It turns out to be much better than
I expected: the JVM will start up, compile things, etc. with just:
&lt;code&gt;@critical @default @basic-io @file-system futex rt_sigaction clone&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This actually works as a filter, too: if Java code tries to make a network
connection, it is denied. Or, er, at least, something in that area is denied.
Unfortunately, the JVM cra.. er.. "hard exits" for many of these failures,
as they come through as unexpected asserts:&lt;/p&gt;
&lt;p&gt;e.g.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Assertion 'sigprocmask_many(SIG_BLOCK, &amp;amp;t, 14,26,13,17,20,29,1,10,12,27,23,28, -1) &amp;gt;= 0' failed at ../src/nss-myhostname/nss-myhostname.c:332, function _nss_myhostname_gethostbyname3_r(). Aborting.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;It then prints out loads of uninitialised memory, as it doesn't expect
&lt;a href="https://github.com/FauxFaux/jdk9-hotspot/blob/master/src/os/posix/vm/os_posix.cpp#L237"&gt;uname to fail&lt;/a&gt;.
e.g.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Memory: 4k page, physical 10916985944372480k(4595315k free), swap 8597700727024688k(18446131672566297518k free)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;uname: [box][box]s[box]&lt;/code&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This demonstrates only one of the operation modes for &lt;code&gt;seccomp&lt;/code&gt;. Note that, as of
today, the Wikipedia page is pretty out of date, and the manpage is outright misleading.
Consider reading
&lt;a href="http://man7.org/linux/man-pages/man3/seccomp_rule_add.3.html"&gt;man:seccomp_rule_add(3)&lt;/a&gt;,
part of libseccomp2, to work out what's available.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Summary: Hardening good, hardening hard. Run your integration test suite under
&lt;code&gt;seccomp-filter.py --blacklist @obsolete @debug @reboot @swap @resources&lt;/code&gt; and see
if you can at least get to that level of security?&lt;/p&gt;</content><link href="https://blog.goeswhere.com/2017/02/seccomp-tool/"/><published>2026-02-22T14:30:08.344927+00:00</published></entry><entry><id>https://blog.goeswhere.com/2017/02/working-around-linux/</id><title>Busy work: pasane and syscall extractor</title><updated>2026-02-22T14:30:08.344927+00:00</updated><content>&lt;p&gt;Today, I wrote
&lt;a href="https://github.com/japaric/syscall.rs/pull/15/commits/847debb0a1de5f756fed124fea671ad722ba99ab#diff-b35c4def919470d7d2138ba45bed4adc"&gt;a load of Python&lt;/a&gt;
and
a &lt;em&gt;load&lt;/em&gt; of C to work around
pretty insane problems in Linux, my choice of OS for development.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://github.com/FauxFaux/pasane"&gt;pasane&lt;/a&gt; is a command-line volume
control that doesn't mess up channel balance. This makes it unlike all
of the other volume control tools I've tried that you can reasonably
drive from the command line.&lt;/p&gt;
&lt;p&gt;It's necessary to change volume from the command line as
I &lt;a href="https://github.com/FauxFaux/rc/commit/91964555ae85a2464b8dc7bb37847eb5423645e8"&gt;launch commands in response to hotkeys&lt;/a&gt;
(e.g. to implement the &lt;code&gt;volume+&lt;/code&gt; button on my keyboard). It's also
occasionally useful to change the volume via. SSH. Maybe there's another
option? Maybe something works via. dbus? This seemed to make the most
sense at the time, and isn't too awful.&lt;/p&gt;
&lt;p&gt;Am I insane?&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next up: Some code to
&lt;a href="https://github.com/japaric/syscall.rs/pull/15/commits/847debb0a1de5f756fed124fea671ad722ba99ab#diff-b35c4def919470d7d2138ba45bed4adc"&gt;parse the list of syscalls from the Linux source tree&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It turns out that it's useful to have these numbers available in other
languages, such that you can pass them to &lt;a href="/2017/02/seccomp-tool/"&gt;tools&lt;/a&gt;,
so that you can decode raw syscall numbers you've seen, or simply so that
you can make the syscalls.&lt;/p&gt;
&lt;p&gt;Anyway, they are not available in the Linux source. What? Yes, for most
architectures, this table is not available. It's there on &lt;code&gt;i386&lt;/code&gt;, &lt;code&gt;amd64&lt;/code&gt;,
and &lt;code&gt;arm&lt;/code&gt; (32-bit), but not for anything else. You have to.. uh.. build
a kernel for one of those architectures, then compile C code to get the
values. Um. What?&lt;/p&gt;
&lt;p&gt;This &lt;em&gt;is&lt;/em&gt; insane.&lt;/p&gt;
&lt;p&gt;The Python code (linked above) does a reasonably good job of extracting
them from this insanity, and generating the tables for a couple more
arches.&lt;/p&gt;
&lt;p&gt;I needed to do this so I can copy a file efficiently. I think. I've kind
of lost track. Maybe I am insane.&lt;/p&gt;</content><link href="https://blog.goeswhere.com/2017/02/working-around-linux/"/><published>2026-02-22T14:30:08.344927+00:00</published></entry><entry><id>https://blog.goeswhere.com/2017/03/find-deleted-checkrestart/</id><title>find-deleted: checkrestart replacement</title><updated>2026-02-22T14:30:08.344927+00:00</updated><content>&lt;p&gt;&lt;a href="https://manpages.debian.org/testing/debian-goodies/checkrestart.1.en.html"&gt;checkrestart&lt;/a&gt;, part of
&lt;a href="https://packages.debian.org/debian-goodies"&gt;debian-goodies&lt;/a&gt;,
checks what you might need to restart. You can run it after a system
update, and it will find running processes using outdated libraries.
If these can be restarted, and there's no new kernel updates, then
you can save yourself a reboot.&lt;/p&gt;
&lt;p&gt;However, &lt;code&gt;checkrestart&lt;/code&gt; is pretty dated, and has some weird behaviour.
It frequently reports that there are things needing a restart, but
that it doesn't feel like telling you what they are. (This makes me
moderately angry). It's pretty bad at locating services on a
systemd-managed system. It tries to look through Debian packages,
making it Debian specific (along with unreliable). This is especially
odd, because systemd knows what pid belongs to a unit, as does &lt;code&gt;/proc&lt;/code&gt;,
and...&lt;/p&gt;
&lt;p&gt;Instead of fixing it, I have rewritten it from scratch.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/FauxFaux/find-deleted"&gt;find-deleted&lt;/a&gt; is a tool
to find deleted files which are still in use, and to suggest systemd
units to restart.&lt;/p&gt;
&lt;p&gt;The default is to try and be helpful:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;% find-deleted
 * blip
   - sudo systemctl restart mysql.service nginx.service
 * drop
   - sudo systemctl restart bitlbee.service
 * safe
   - sudo systemctl restart fail2ban.service systemd-timesyncd.service tlsdate.service
 * scary
   - sudo systemctl restart dbus.service lxc-net.service lxcfs.service polkitd.service
Some processes are running outside of units, and need restarting:
 * /bin/zsh5
  - [1000] faux: 7161 17338 14539
 * /lib/systemd/systemd
  - [1000] faux: 2082
  - [1003] vrai: 8551 8556
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, it is telling us that a number of services need a restart.
The services are categorised based on some patterns defined in the
associated configuration file, &lt;code&gt;deleted.yml&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For this machine, I have decided that restarting &lt;code&gt;mysql&lt;/code&gt; and &lt;code&gt;nginx&lt;/code&gt;
will cause a &lt;code&gt;blip&lt;/code&gt; in the service to users; I might do it at an off-peak
time, or ensure that there's other replicas of the service available
to pick up the load.&lt;/p&gt;
&lt;p&gt;My other categories are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;drop: A loss of service will happen that will be annoying for users.&lt;/li&gt;
&lt;li&gt;safe: These services could be restarted all day, every day, and nobody would notice.&lt;/li&gt;
&lt;li&gt;scary: Restarting these may log you out, or
    &lt;a href="https://github.com/systemd/systemd/issues/2748"&gt;cause the machine to stop functioning&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;other: things which don't currently have a classification&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you're happy with its suggestions, you can copy-paste the above commands,
or you can run it in a more automated fashion:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl restart $(find-deleted --show-type safe)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can effectively be run through provisioning tools, on a whole selection
of machines, if you trust your matching rules! I have done this with a much
more primitive version of this tool at a previous employer.&lt;/p&gt;
&lt;p&gt;It can also print the full state that it's working from, using &lt;code&gt;--show-paths&lt;/code&gt;.&lt;/p&gt;</content><link href="https://blog.goeswhere.com/2017/03/find-deleted-checkrestart/"/><published>2026-02-22T14:30:08.344927+00:00</published></entry><entry><id>https://blog.goeswhere.com/2017/07/java-9-rebuild/</id><title>Rebuilding Debian with Java 9</title><updated>2026-02-22T14:30:08.344927+00:00</updated><content>&lt;p&gt;It's about three months until
&lt;a href="http://www.java9countdown.xyz/"&gt;Java 9 is supposed to be released&lt;/a&gt;.
Debian contains around 1,200 packages that build against Java 8.
I have been trying to build them with Java 9.&lt;/p&gt;
&lt;p&gt;It's not been going well.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://lists.debian.org/debian-java/2017/06/msg00038.html"&gt;The first attempt&lt;/a&gt;
found an 87% failure rate, the majority of which were either:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;toolchain issues (which are for Debian to fix)
    (e.g. &lt;a href="https://bugs.debian.org/866411"&gt;maven/guice needing new cglib&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-source&lt;/code&gt; and &lt;code&gt;-target&lt;/code&gt; being old, unsupported values.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is too bad to get an idea of what's actually broken, so I gave up.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://lists.debian.org/debian-java/2017/07/msg00010.html"&gt;The second attempt&lt;/a&gt;
has gone better, only 57% failures. This had a number of issues fixed, but
there's still a large number of problems masked by toolchain failures.&lt;/p&gt;
&lt;p&gt;However, some real Java 9 breakages are coming to the fore!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;90 packages are hitting &lt;a href="https://rbuild.fau.xxx/2017-07-02/modules/"&gt;module-based accessibility rules&lt;/a&gt;,
    although maybe many of these are bugs in &lt;code&gt;gradle&lt;/code&gt;. These are the kind of
    bug that it may be hard to fix in your own software, so it's slightly
    worrying to see so many of them.&lt;/li&gt;
&lt;li&gt;15 packages are using &lt;a href="https://rbuild.fau.xxx/2017-07-02/keyword/"&gt;underscore or enum as a keyword&lt;/a&gt;,
    which hopefully should be easy to fix everywhere.&lt;/li&gt;
&lt;li&gt;9 packages have new &lt;a href="https://rbuild.fau.xxx/2017-07-02/cast/"&gt;compile failures around casting&lt;/a&gt;,
    which may be compiler improvements, or bugs. Exciting!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Oh, and 135 packages have &lt;a href="https://rbuild.fau.xxx/2017-07-02/unknown/"&gt;an unknown problem&lt;/a&gt;,
so maybe there's a whole other class of bug I've missed.&lt;/p&gt;
&lt;p&gt;This is (obviously) an ongoing &lt;a href="https://github.com/FauxFaux/debjdk9"&gt;project&lt;/a&gt;,
but I thought I'd write up what I'd seen so far.&lt;/p&gt;
&lt;p&gt;Also, I wanted to mention how cool it was to hack up a dashboard for your
&lt;a href="https://github.com/FauxFaux/debjdk9/blob/master/Makefile"&gt;ghetto make/Docker build process&lt;/a&gt;
in &lt;a href="https://github.com/FauxFaux/debjdk9/blob/d2a4a6c692211f7e819a4909d78d2d060d2a7a24/classify.sh"&gt;ghetto shell&lt;/a&gt;,
although slightly less ghetto than the
&lt;a href="https://github.com/FauxFaux/debjdk9/blob/fe991263eb22510fa8ac45f2d8978dc667784a46/classify.sh"&gt;previous shell&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Every 2.0s: ./classify.sh

ascii           cast            deps            doclint         javadoc         keyword         modules         unknown         version
47 total        9 total         203 total       82 total        165 total       15 total        83 total        114 total       206 total
====            ====            ====            ====            ====            ====            ====            ====            ====
antelope        charactermanaj  access-*hecker  android*-tools  access-*hecker  avalon-*mework  activem*otobuf  adql            389-adm*onsole
axis            dom4j           activem*tiveio  antlr4          akuma           axis            android*ork-23  aspectj         389-ds-console
azureus         electric        activemq        args4j          animal-sniffer  biojava-live    android*dalvik  aspectj*plugin  airport-utils
clirr           findbugs        activem*otobuf  bindex          annotat*ndexer  bnd             android*oclava  bouncycastle    android*-tools
cmdreader       jajuk           afterburner.fx  cdi-api         antlr3          dbus-java       android*silver  bsh             antlr
cortado         jsymphonic      akuma           classycle       apache-log4j2   jalview         android*inding  closure*mpiler  artemis
cronometer      libjaud*r-java  animal-sniffer  commons-math3   apache-mime4j   javacc4         android*ibcore  cofoja          beansbinding
dita-ot         olap4j          annotat*ndexer  ditaa           async-h*client  java-gnome      android*ibrary  commons-jcs     bindex
eclipselink     sweethome3d     antlr3          felix-g*-shell  axmlrpc         jmol            android*apksig  convers*ruptor  biojava-live
eclipse                         antlr4          fest-assert     bcel            jruby-openssl   android*s-base  davmail         biomaj
entagged                        apache-log4j2   fest-reflect    bridge-*jector  libcomm*g-java  android*ls-swt  diffoscope      brig
fop                             args4j          fest-util       bsaf            libxml-*1-java  android*helper  dnsjava         brltty
geronim*0-spec                  atinjec*jsr330  ganymed-ssh2    build-h*plugin  libxpp2-java    ant             dumbster        cadencii
imagej                          bcel            gentlyw*-utils  canl-java       mvel            apktool         eclipse*nyedit  castor
jasmin-sable                    bridge-*jector  glassfish       cglib           squareness      basex           eclipse-cdt     cdi-api
jas                             build-h*plugin  hdf5            commons*nutils                  bintray*t-java  eclipse*config  ceph
jasypt                          carrots*h-hppc  hessian         commons*ration                  biojava4-live   eclipse-eclox   cobertura
javacc4                         cglib           intelli*ations  commons-csv                     easybind        eclipse-emf     coco-java
javaparser                      checkstyle      jacksum         commons-io                      eclipse-mylyn   eclipse-gef     colorpicker
jets3t                          codenarc        jcm             commons*vaflow                  eclipse-wtp     eclipse*clipse  commons*client
jgromacs                        commons*nutils  jfugue          commons-jci                     eclipse-xsd     eclipse*es-api  concurr*t-dfsg
king                            commons*ration  jmock           commons-math                    freeplane       eclipse-rse     cvc3
knopfle*h-osgi                  commons-csv     jnr-ffi         cssparser                       gant            eclipse*clipse  db5.3
libcds-*t-java                  commons-io      jpathwatch      csvjdbc                         gradle-*plugin  emma-coverage   dbus-java
libcomm*g-java                  commons*vaflow  jsurf-alggeo    dirgra                          gradle          gdcm            dicomscope
libidw-java                     commons-jci     jts             dnssecjava                      gradle-*otobuf  geronim*upport  ditaa
libiscwt-java                   commons-math    libcds-*c-java  dokujclient                     gradle-*plugin  gettext         docbook*-saxon
libitext-java                   commons-parent  libcomm*c-java  doxia-s*etools                  graxxia         gluegen2        doxia
libjdbm-java                    commons-vfs     libcomm*4-java  dtd-parser                      groovycsv       gnome-split     easyconf
libjt400-java                   core-ca*lojure  libcomm*2-java  easymock                        groovy          h2database      excalib*logger
libstax-java                    cssparser       libhac-java     felix-b*sitory                  gs-collections  ha-jdbc         excalib*logkit
libvldo*g-java                  data-xm*lojure  libhtml*r-java  felix-f*mework                  htsjdk          hdrhistogram    f2j
libxpp3-java                    dirgra          libirclib-java  felix-g*ommand                  ice-bui*gradle  icu4j           felix-osgi-obr
livetri*jsr223                  dnssecjava      libjaba*t-java  felix-g*untime                  insubstantial   icu4j-4.2       fontchooser
mathpiper                       dokujclient     libjgoo*n-java  felix-shell                     ivyplusplus     icu4j-4.4       ganymed-ssh2
maven-a*helper                  doxia           libjhla*s-java  felix-s*ll-tui                  jabref          icu4j-49        gentlyw*-utils
metastudent                     doxia-s*etools  libjoda*e-java  felix-utils                     jackson*tabind  istack-commons  geogebra
naga                            dtd-parser      libjsonp-java   geronim*0-spec                  jackson*-guava  jakarta-jmeter  gridengine
ognl                            easymock        libjsr1*y-java  geronim*1-spec                  java3d          janino          healpix-java
&lt;/code&gt;&lt;/pre&gt;</content><link href="https://blog.goeswhere.com/2017/07/java-9-rebuild/"/><published>2026-02-22T14:30:08.344927+00:00</published></entry><entry><id>https://blog.goeswhere.com/2017/10/arduino-radio/</id><title>Arduino radio communication</title><updated>2026-02-22T14:30:08.344927+00:00</updated><content>&lt;p&gt;Once again, I have ordered the wrong hardware from eBay.&lt;/p&gt;
&lt;p&gt;This time, it was a set of 433MHz radio transceivers for "Arduino".
The majority of these come with embedded circuitry for sending and
receiving bits. The ones I ordered, however, did not.&lt;/p&gt;
&lt;p&gt;The transmitter emits power when its data line is powered. The
receiver emits a varying voltage, which can be ADC'd back into
a value, ~1 -&amp;gt; ~800. This is not digital.&lt;/p&gt;
&lt;p&gt;I decided to do everything from scratch. Everything.&lt;/p&gt;
&lt;p&gt;A useful simple radio protocol is known as "OOK" or "ASK":
You turn the radio on when you're sending a "1", you turn it
off when you're not.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/FauxFaux/arduino-manual-radio/blob/d4a5afc5dea0897d890a96a887f1da1b4de3e728/infrequent_transmit/infrequent_transmit.ino#L1-L14"&gt;The transmitter&lt;/a&gt;
is amazingly simple; you turn on the radio, and you turn it off.
These fourteen lines of code actually send two bits, for reasons
which will become horrifying later.&lt;/p&gt;
&lt;p&gt;Or now. Radio is incredibly unreliable. This is worked around
by layering all kinds of encodings / checksums together, and
hoping everything works out. (Narrator: It doesn't work out.)&lt;/p&gt;
&lt;p&gt;The first type of encoding used is called "Manchester Encoding".
This involves doubling the amount of data you send, but gives you
lots of scope for detecting problems. For a &lt;code&gt;1&lt;/code&gt;, you send &lt;code&gt;01&lt;/code&gt;,
and for a &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;10&lt;/code&gt;. That is, if you see a &lt;code&gt;111&lt;/code&gt; or a &lt;code&gt;000&lt;/code&gt; in
your stream, you know something's gone wrong.&lt;/p&gt;
&lt;p&gt;So, to send the number &lt;code&gt;6&lt;/code&gt;, binary &lt;code&gt;0110&lt;/code&gt;, we're going to send
&lt;code&gt;10_01_01_10&lt;/code&gt;. This is why the sending code
&lt;a href="https://github.com/FauxFaux/arduino-manual-radio/blob/d4a5afc5dea0897d890a96a887f1da1b4de3e728/infrequent_transmit/infrequent_transmit.ino#L16-L22"&gt;sends two bits&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The receiver's job is much more horrifying. The receiver has
"samples" from a radio (a three-digit integer), at unknown time
intervals. The minimum value read varies wildly with environmental
conditions, as does the peak value (the value you hope to see
when the transmitter is sending).&lt;/p&gt;
&lt;p&gt;For this purpose, the receiver has multiple levels of filtering.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/FauxFaux/arduino-manual-radio/blob/d4a5afc5dea0897d890a96a887f1da1b4de3e728/analog_rolling/analog_rolling.ino#L70-L103"&gt;First&lt;/a&gt;,
it takes a &lt;code&gt;fast&lt;/code&gt; moving average over the received signal,
and a "slow" moving average over the &lt;code&gt;background&lt;/code&gt; noise (the average
of all samples), and our guess as to the &lt;code&gt;high&lt;/code&gt; value.
If the &lt;code&gt;fast&lt;/code&gt; moving average is greater than half way up this band,
it's probably a &lt;code&gt;hi&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This can be observed in the code by enabling &lt;code&gt;DEBUG_BACKGROUND&lt;/code&gt;,
and rebooting the board. This initially has a bad idea of what
the noise environment looks like, so will look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;background: 8 sig_high:99 high:47 trigger:53 -- ..XXX.XXXXXXX.XXXXXXXXXXXXXXX...................................XXX.............................................................
background: 6 sig_high:96 high:87 trigger:51 -- .....................................................XXX....XX..................................................................
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, it's got a very narrow range, so triggering too often and
emitting lots of nonsense bits (the &lt;code&gt;XXX&lt;/code&gt;s). After a while, it will
adjust:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;background: 28 sig_high:159 high:757 trigger:93 -- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX....X..XX..XXX...............................................................................
background: 27 sig_high:163 high:450 trigger:95 -- ................................................................................................................................
background: 26 sig_high:165 high:26 trigger:95 -- ................................................................................................................................
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, its background estimate is higher, but its &lt;code&gt;sig_high&lt;/code&gt; estimate
is much higher, so the trigger is higher, and it doesn't
incorrectly trigger at all. (Those &lt;code&gt;XXX&lt;/code&gt;s are part of a real signal.)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/FauxFaux/arduino-manual-radio/blob/d4a5afc5dea0897d890a96a887f1da1b4de3e728/analog_rolling/analog_rolling.ino#L107-L136"&gt;Second&lt;/a&gt;,
we "decimate" this signal down a lot, by taking a binary average of
finite blocks. As the sample rate is still significantly higher than
the length of a bit, it does not matter that these are not well
aligned. We then count the length of runs of each state we see,
ignoring single errors and overly long runs.&lt;/p&gt;
&lt;p&gt;As Arduinos, and the radio hardware, don't do anything like what
you tell them, it's impossible to know in advance how long (in
milliseconds) a pulse will be, or how long of a run represents a
&lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Fixing this problem is called "clock recovery", we need to guess
how long a pulse is according to us, regardless of what the sender
thinks it's doing.&lt;/p&gt;
&lt;p&gt;Manchester encoding helps with clock recovery. The transmitter
sends a &lt;a href="https://github.com/FauxFaux/arduino-manual-radio/blob/d4a5afc5dea0897d890a96a887f1da1b4de3e728/infrequent_transmit/infrequent_transmit.ino#L48-L56"&gt;"preamble"&lt;/a&gt;
of zeros, which are encoded as &lt;code&gt;10101010&lt;/code&gt;, that is, a series of
pulses. The receiver &lt;a href="https://github.com/FauxFaux/arduino-manual-radio/blob/d4a5afc5dea0897d890a96a887f1da1b4de3e728/analog_rolling/analog_rolling.ino#L151-L170"&gt;uses this&lt;/a&gt;
to guess how long a pulse is, and to check the guess is correct.&lt;/p&gt;
&lt;p&gt;This code is looking for a high (and keeping the length of this
high), then a low of the same length, then another high/low.
If we see these, then we're reasonably confident we're
synchronised to the signal.&lt;/p&gt;
&lt;p&gt;There's a &lt;code&gt;DEBUG_CLOCK&lt;/code&gt; which watches this phase working:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;7: (XXXXXXX_.......) 0 (XXXXXXX_.......) 0 (_XXXXXXX_..............) 0 (_XXXXXXXXXXXXXX) 1 (...................) end (encoding violated)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, it's guessed the length of seven, then seen a two normal
valid &lt;code&gt;0&lt;/code&gt;s, then a &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;1&lt;/code&gt;, with the double-length &lt;code&gt;0&lt;/code&gt; pulse in
the centre. After this, the transmitter went silent, and hence
we saw a stream of &lt;code&gt;000&lt;/code&gt;s. Three zeros is invalid in Manchester encoding
so we stopped decoding.&lt;/p&gt;
&lt;p&gt;So! We've got a stream of bits, and an end. From this, we need
to find the start of the message. I've chosen to implement this
by sending a long stream of zeros, then two ones, then immediately
the data. This scheme doesn't seem ideal, but it does work.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://github.com/FauxFaux/arduino-manual-radio/blob/d4a5afc5dea0897d890a96a887f1da1b4de3e728/analog_rolling/analog_rolling.ino#L220-L245"&gt;decoder waits for this condition to happen&lt;/a&gt;,
then starts to &lt;a href="https://github.com/FauxFaux/arduino-manual-radio/blob/d4a5afc5dea0897d890a96a887f1da1b4de3e728/analog_rolling/analog_rolling.ino#L247-L266"&gt;read bytes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The bytes are transmitted as 8-bits (MSB last, unlike normal),
with a parity bit. This explains the
&lt;a href="https://github.com/FauxFaux/arduino-manual-radio/blob/d4a5afc5dea0897d890a96a887f1da1b4de3e728/infrequent_transmit/infrequent_transmit.ino#L24-L30"&gt;last piece of unexplained code&lt;/a&gt;
in the transmitter!&lt;/p&gt;
&lt;p&gt;There's also a debugger for this, in &lt;code&gt;DEBUG_DECODE&lt;/code&gt;. Here,
we can see it waiting for &lt;code&gt;XX&lt;/code&gt; (the second accepted &lt;code&gt;X&lt;/code&gt; is
bracketed), then reading the next nine bits and checking the
parity. Note that there's no synchronisation for the second
byte, as it's assumed we're still synchronised:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;..X(X)...XX.... =&amp;gt; 24 (parity: 00)
X..XX..X. =&amp;gt; 153 (parity: 00)
X......X. =&amp;gt; 129 (parity: 00)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, a failure looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;X(.X(..X(X)..X.X.... =&amp;gt; 20 (parity: 00)
..X.X...X(X)...XX.... =&amp;gt; 24 (parity: 00)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To be honest, I have no real idea what's gone wrong here.
The cleaned up data stream looks like &lt;code&gt;101001100101000000101&lt;/code&gt;.
The &lt;code&gt;001100&lt;/code&gt; could be synchronisation, or it could be the
encoded "24". Argh! Why would you pick this sequence for
temperatures?! Why?&lt;/p&gt;
&lt;p&gt;The actual data being sent is a temperature reading, encoded
as two bytes, &lt;code&gt;(int)Celsius&lt;/code&gt;, and the decimal part as a single
byte.&lt;/p&gt;
&lt;p&gt;As corruption was still getting through at this level, an
&lt;em&gt;extra&lt;/em&gt; checksum is computed, as the &lt;code&gt;xor&lt;/code&gt; of these two bytes
together. Finally, it's mostly reliable. With all the debugging
disabled, it looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Value checks out: 24.70
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Shame the temperature sensor varies (by about 2C) from my other
sensors. It also loses about half the messages to errors, as
there's no error recovery at all.&lt;/p&gt;
&lt;p&gt;Wasn't that fun?&lt;/p&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;What would a normal software decoder look like for this?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Probably about as bad. I wrote an example &lt;code&gt;FSK&lt;/code&gt; decoder as part
of a radio manipulation tool I wrote, named &lt;a href="https://github.com/FauxFaux/quadrs#worked-example-fsk"&gt;quadrs&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How far is this radio transmitting?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Um.&lt;/p&gt;
&lt;p&gt;&lt;img src="/files/2017-10-arduino-photo.jpg" alt="breadboard setup photo"/&gt;&lt;/p&gt;
&lt;p&gt;About three centimetres.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What's the data rate?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://asciinema.org/a/dDFAczfUyMQxlhWoRft9O02pl"&gt;Horrendeous&lt;/a&gt;.&lt;/p&gt;</content><link href="https://blog.goeswhere.com/2017/10/arduino-radio/"/><published>2026-02-22T14:30:08.344927+00:00</published></entry><entry><id>https://blog.goeswhere.com/2018/01/crypto/</id><title>Cryptography overview</title><updated>2026-02-22T14:30:08.344927+00:00</updated><content>&lt;p&gt;The world's understanding of cryptography, the guarantees provided,
and the practical safety and limitations, is lacking.&lt;/p&gt;
&lt;p&gt;Cryptography, and computer security in general, is discussed in terms
of some &lt;em&gt;use-cases&lt;/em&gt;. A &lt;em&gt;use-case&lt;/em&gt; is addressed by combining some
&lt;em&gt;primitives&lt;/em&gt;, and there's frequently multiple different &lt;em&gt;algorithms&lt;/em&gt; which
can provide a &lt;em&gt;primitive&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;First, let's look at some &lt;em&gt;use-cases&lt;/em&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I want to do some banking on my bank's website.&lt;/li&gt;
&lt;li&gt;My bank wants to know that my genuine EMV ("Chip and Pin") card
    is doing a purchase.&lt;/li&gt;
&lt;li&gt;I want to store a big file privately, but only remember a short password.&lt;/li&gt;
&lt;li&gt;I want the recipient to know that it was actually me that wrote an email.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of these mention cryptography, or even really that security is expected,
but the requirement for security is implied by the context.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Let's pick one of these, and have a look at what's involved: "I want to store
a big file privately, but only remember a short password.".&lt;/p&gt;
&lt;p&gt;This normally comes up with backups. You want to store your data (your family
photos?) on someone else's computer (Amazon's?), but you don't trust them. You
want to remember a password, and have this password (and only this password) be
able to unlock your precious data.&lt;/p&gt;
&lt;p&gt;This is normally realised by:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Making a key from the user's password.&lt;/li&gt;
&lt;li&gt;Using this key to scramble and protect the data.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Those are our two &lt;em&gt;primitives&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;After these steps have been applied, it should be impossible for anyone to
un-scramble the data without guessing the password. It's also impossible for anyone
to modify the data without us realising.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Everything one of our use-cases, and the vast majority of use-cases in the real
world, can be built from a small set of &lt;em&gt;primitives&lt;/em&gt;. Here's a list, including the
two from above:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Deriving a key from a password.&lt;/li&gt;
&lt;li&gt;Using a key to scramble and protect data.&lt;/li&gt;
&lt;li&gt;Agreeing on a key with an online, remote computer you know nothing about.&lt;/li&gt;
&lt;li&gt;Protecting something, such that it can only be read by someone you know something about.&lt;/li&gt;
&lt;li&gt;Proving you wrote something, given the other computer already knows something about you. &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That's it. Those are our operations. Now, we can build the whole world.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;But first, a quick note on security: In the modern Internet era, since ~1993 (25 years!),
only #5 has &lt;em&gt;ever&lt;/em&gt; been practically attacked in any way. The others are practically perfect. &lt;/p&gt;
&lt;p&gt;There have been lots of security problems, and things have had to change to remain secure.
These have mostly been:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Computers have got fast enough that it's been possible to increase some of the
    "security parameters" in some of the primitives, long before computers have
    practically been fast enough to actually &lt;a href="https://en.wikipedia.org/wiki/Brute-force_attack"&gt;hurt any of the primitives&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;People have used weaker primitives, or kept old or weak systems running long past
    when they should have been turned off. That, or they have been
    &lt;a href="https://en.wikipedia.org/wiki/56-bit_encryption"&gt;legally mandated&lt;/a&gt;
    to use these weaker systems.&lt;/li&gt;
&lt;li&gt;Software bugs. The primitives are complicated, built from lots of algorithms, and the
    algorithms are hard enough to implement correctly on their own. It's hard to test, too!
    A lot of components are
    &lt;a href="https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One"&gt;much more complicated than necessary&lt;/a&gt;,
    but we're bad at fixing that.&lt;/li&gt;
&lt;li&gt;Problems with algorithms which don't translate to real world problems for most
    use-cases, or that are easy to mitigate once discovered, assuming the relevant people
    actually adopt the mitigations.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;Now we understand what we have to build stuff from, let's try and attack the hardest
problem: "I want to do some banking on my bank's website."&lt;/p&gt;</content><link href="https://blog.goeswhere.com/2018/01/crypto/"/><published>2026-02-22T14:30:08.344927+00:00</published></entry><entry><id>https://blog.goeswhere.com/2018/10/kill-desktop/</id><title>kill-desktop and TUIs</title><updated>2026-02-22T14:30:08.344927+00:00</updated><content>&lt;p&gt;&lt;a href="https://github.com/FauxFaux/kill-desktop"&gt;kill-desktop&lt;/a&gt; tries to get your
"X" applications to exit cleanly, such that you can shutdown, or reboot.&lt;/p&gt;
&lt;p&gt;"Watch" the &lt;a href="https://github.com/FauxFaux/kill-desktop#demo"&gt;"demo" in the repository readme&lt;/a&gt;,
or try it out for yourself:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cargo install kill-desktop&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Many people just reboot. This risks losing unsaved work, such as documents,
the play position in your media player, or even
&lt;a href="https://bugzilla.redhat.com/show_bug.cgi?id=1141137"&gt;the shell history in your shell&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This feature is typically built in to desktop environments, but somewhat
lacking in the more minimalist of linux window managers, such as my favourite,
&lt;a href="https://i3wm.org/"&gt;i3wm&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Even the more complex solutions, such as the system built into Windows, do
not deal well with naughty applications; ones that will just go hide in the
tray when you try to close them, or that show dialogs a while after you
asked them to exit.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;kill-desktop&lt;/code&gt; attempts to solve this problem by keeping track of the state
of the system, and offering you ways to progress. If one of these naughty
hiding applications merely hides when you close the window, &lt;code&gt;kill-desktop&lt;/code&gt;
doesn't forget. It tracks the process of that window, waiting for it to go
away. If it is not going away, you are able to ask the &lt;em&gt;process&lt;/em&gt; to exit. Or
just shut down. It's probably a bad application anyway.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Interesting learnings from this project:&lt;/p&gt;
&lt;p&gt;Firstly, writing an interface was a bit of a pain. I wanted to be able to
prompt the user for an action, but also be able to show them updates. It is
not possible to do this without
&lt;a href="https://play.rust-lang.org/?gist=b2f0144b92a7ac4a5322ab2e1d5a6887&amp;amp;version=stable&amp;amp;mode=debug&amp;amp;edition=2015"&gt;threads&lt;/a&gt;,
as there is no way to do a non-blocking read from &lt;code&gt;stdin&lt;/code&gt;. This surprised me.&lt;/p&gt;
&lt;p&gt;You can't even read a single character (think &lt;code&gt;Continue? y/n&lt;/code&gt;) without messing
with the terminal settings, which needs very low level, non-portable libraries.&lt;/p&gt;
&lt;p&gt;There are nicely packaged solutions to this problem, like
&lt;a href="https://docs.rs/termion/1.5.1/termion/fn.async_stdin.html"&gt;&lt;code&gt;termion's async_stdin&lt;/code&gt;&lt;/a&gt;
but this ended up messing with the terminal more than required (it puts it all
the way into &lt;code&gt;raw&lt;/code&gt; mode, instead of stopping at &lt;code&gt;-icanon&lt;/code&gt;). I
&lt;a href="https://github.com/FauxFaux/kill-desktop/blob/3bebe9fc3454f724c9a9a3fa24e2b537a2dff066/src/term.rs"&gt;wrote my own&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Secondly, it's amazing how a relatively simple application can end up tracking
&lt;a href="https://github.com/FauxFaux/kill-desktop/commit/1e338fb40fb381d9e4406148b006dee84af612ec"&gt;more state than expected&lt;/a&gt;, and
&lt;a href="https://github.com/FauxFaux/kill-desktop/commit/c7727611ce8a7fae04ade76a70675f17c0997db1"&gt;manually diffing that state&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also spent time
&lt;a href="https://github.com/FauxFaux/kill-desktop/commit/1e338fb40fb381d9e4406148b006dee84af612ec#diff-639fbc4ef05b315af92b4d836c31b023R183"&gt;moving errors to be part of the domain&lt;/a&gt;,
which isn't even fully surfaced yet. It amazes me how much code ends up being
dedicated to error handling, even in a language with excellent terse error
handling. (Terminology from
&lt;a href="https://www.youtube.com/watch?v=3RtLCav0Bp4"&gt;Feathers&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;It's also ended up with &lt;em&gt;nine&lt;/em&gt; dependencies, although between four and six of
those are for loading the (trivial) config file, which could be done better.&lt;/p&gt;</content><link href="https://blog.goeswhere.com/2018/10/kill-desktop/"/><published>2026-02-22T14:30:08.344927+00:00</published></entry><entry><id>https://blog.goeswhere.com/2018/12/year-of-projects/</id><title>2018 in (failed) projects</title><updated>2026-02-22T14:30:08.344927+00:00</updated><content>&lt;p&gt;I have written a large mass of code this year, primarily in Rust.&lt;/p&gt;
&lt;p&gt;With only one exception, none of this has reached the 'blog post' level
of maturity. Here lies a memorial for these projects, perhaps as
a reminder to me to resurrect them.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://github.com/FauxFaux"&gt;Github's contribution chart&lt;/a&gt; gives a good
indication of just how much code has been written. Clearly visible are
some holidays, and the associated productivity peaks on either side:&lt;/p&gt;
&lt;p&gt;&lt;img alt="github contributions" src="/images/2018-12-31-gh-contributions.png" /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Some focuses this "year" (Nov 2017+):&lt;/p&gt;
&lt;h3&gt;Archives and storage&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/FauxFaux/contentin"&gt;contentin&lt;/a&gt; and
&lt;a href="https://github.com/FauxFaux/splayers"&gt;splayers&lt;/a&gt; recursively unpack an
archive, supporting multiple formats. You have a &lt;code&gt;gzip&lt;/code&gt; file, on an
&lt;a href="https://github.com/FauxFaux/ext4-rs"&gt;ext4 filesystem&lt;/a&gt;, inside a
&lt;code&gt;tar.bzip2&lt;/code&gt; archive, inside a Debian package? No problem.&lt;/p&gt;
&lt;p&gt;The aim here was to "ingest" large volumes of "stuff", either for
comparison (e.g. &lt;a href="https://diffoscope.org/"&gt;diffoscope&lt;/a&gt;, from the
Reproducible Builds project), or for indexing and search.&lt;/p&gt;
&lt;p&gt;Speaking of which, &lt;a href="https://github.com/FauxFaux/deb2pg"&gt;deb2pg&lt;/a&gt;
demonstrates various ways &lt;em&gt;not&lt;/em&gt; to build an indexing search engine
for a large quantity of "stuff".&lt;/p&gt;
&lt;p&gt;While working on these, I became a bit obsessed with how bad &lt;code&gt;gzip&lt;/code&gt;
is. &lt;code&gt;gzip&lt;/code&gt;ing a file, then running it through any kind of indexing,
or even other compression, gives very poor results. &lt;em&gt;Very&lt;/em&gt; poor.
&lt;a href="https://github.com/FauxFaux/rezip-rs"&gt;rezip&lt;/a&gt; is a tool to
&lt;em&gt;reversibly&lt;/em&gt; transform &lt;code&gt;gzip&lt;/code&gt; files into a more storable format.
It... never made it. I could complain for hours. See the &lt;a href="https://github.com/FauxFaux/rezip-rs/blob/master/README.md#rezip"&gt;README&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Much of this work was done against/for Debian. Debian's &lt;code&gt;apt&lt;/code&gt; is
not a fun tool to use, so I started rewriting it. &lt;a href="https://github.com/FauxFaux/fapt"&gt;fapt&lt;/a&gt;
can download lists, and provide data in a usable form (e.g. &lt;code&gt;ninja&lt;/code&gt;
build files). &lt;a href="https://github.com/FauxFaux/gpgrv"&gt;gpgrv&lt;/a&gt; is enough
of a &lt;code&gt;gpg&lt;/code&gt; implementation for &lt;code&gt;fapt&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Once you start rewriting &lt;code&gt;apt&lt;/code&gt;, you might as well rewrite the rest
of the build and packaging system, right? &lt;a href="https://github.com/FauxFaux/fbuilder"&gt;fbuilder&lt;/a&gt;
and &lt;a href="https://github.com/FauxFaux/fappa"&gt;fappa&lt;/a&gt; are two ways not to
do that. &lt;code&gt;fappa&lt;/code&gt; needed to talk to Docker, so &lt;a href="https://github.com/FauxFaux/shipliftier"&gt;shipliftier&lt;/a&gt;
has a partial &lt;code&gt;swagger-codegen&lt;/code&gt; implementation for Rust.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Networking&lt;/h3&gt;
&lt;p&gt;Much of the way networking is done and explained for linux is not
ideal.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/FauxFaux/netzact"&gt;netzact&lt;/a&gt; is a replacement for
the parts of &lt;code&gt;netstat&lt;/code&gt; and &lt;code&gt;ss&lt;/code&gt; that people actually use. It has the
performance of &lt;code&gt;ss&lt;/code&gt;, but only one the horrible bugs: no documentation
at all. That one is probably fixable, at least!&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/FauxFaux/pinetcchio"&gt;pinetcchio&lt;/a&gt; continued into
its fourth year, I like to think I made it even worse this year.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/FauxFaux/fdns"&gt;fdns&lt;/a&gt; was going to do something with
DNS but I can't really remember which thing I was going to fix first.
There's so much wrong with DNS.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/FauxFaux/quad-image"&gt;quad-image&lt;/a&gt; is an image hosting
service. It works, I run it. I even tried to add new image formats, like
&lt;a href="https://github.com/FauxFaux/heifers"&gt;heifers&lt;/a&gt;. That was a mistake.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;IRC&lt;/h3&gt;
&lt;p&gt;I still use IRC. The protocol is bad, but at least there are working
clients. Slack Desktop still segfaults on start on Ubuntu 18.10, months
after release, because they don't understand how to use Electron and
nobody can fix it for them.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/FauxFaux/unsnap"&gt;unsnap&lt;/a&gt; is an IRC title bot. Yes,
there are hundreds of others. No, I don't like working with other people's
untested code in untestable plugin frameworks. Thanks for asking.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/FauxFaux/badchat"&gt;badchat&lt;/a&gt; is some kind of IRC thing.
This one might still have some life in it.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;CLI tools&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/FauxFaux/zrs"&gt;zrs&lt;/a&gt; is a re-implementation of &lt;code&gt;z&lt;/code&gt;, the
directory changing tool. It's good, you should use it.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/FauxFaux/sortuniq"&gt;sortuniq&lt;/a&gt; is a more efficient
&lt;code&gt;| sort | uniq&lt;/code&gt;. It supports some of the flags that either tool supports.
This is probably enough of a blog post for that. I use it frequently.&lt;/p&gt;</content><link href="https://blog.goeswhere.com/2018/12/year-of-projects/"/><published>2026-02-22T14:30:08.344927+00:00</published></entry><entry><id>https://blog.goeswhere.com/2019/10/spooky-exit/</id><title>Spooky Exit At A Distance</title><updated>2026-02-22T14:38:53.387404+00:00</updated><content>&lt;p&gt;I am personally opposed to &lt;code&gt;async&lt;/code&gt;, futures, promises; whatever you call it.
It is almost never appropriate for application or library development,
yet widely proposed as a good solution to problems. It
&lt;a href="https://github.com/seanmonstar/reqwest/pull/538"&gt;also&lt;/a&gt;
has
&lt;a href="https://nodejs.org/api/util.html#util_util_promisify_original"&gt;an&lt;/a&gt;
almost
&lt;a href="https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/"&gt;amusingly&lt;/a&gt;
terrible
&lt;a href="https://rust-lang-nursery.github.io/futures-rs/blog/2019/04/18/compatibility-layer.html"&gt;history&lt;/a&gt;
of integration and transition into ecosystems. I plan to explain my
complaints properly in a future post.&lt;/p&gt;
&lt;p&gt;But, we still use it. Let's look at a specific example, in &lt;code&gt;node&lt;/code&gt;,
which I call "Spooky Exit At A Distance".&lt;/p&gt;
&lt;p&gt;Here, we have possibly the simplest &lt;code&gt;async&lt;/code&gt; &lt;code&gt;node&lt;/code&gt; application,
with the "logging prelude" we're going to be using:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;async function main() {
  return 5;
}

main()
  .then((r) =&amp;gt; console.log('returned:', r))
  .catch((e) =&amp;gt; console.error('erroh!', e))
  .finally(() =&amp;gt; console.log('application complete!'));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This prints the return value (&lt;code&gt;5&lt;/code&gt;), and the &lt;code&gt;application complete!&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;(This "prelude" is here because you
&lt;a href="https://github.com/tc39/proposal-top-level-await#ecmascript-proposal-top-level-await"&gt;can't use &lt;code&gt;await&lt;/code&gt; at the top level in &lt;code&gt;node&lt;/code&gt;&lt;/a&gt;,
which is mighty inconvenient here, but I'm sure they have their reasons.)&lt;/p&gt;
&lt;p&gt;Let's add some "real" work to our example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;async function main() {
  const made = await new Promise((resolve, reject) =&amp;gt; {
    // ... do some work ...
    resolve(2);
  });
  return made + 3;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This prints the same thing as the previous example, in a less direct way.
&lt;code&gt;await&lt;/code&gt; causes us to hand-off control from &lt;code&gt;main&lt;/code&gt; to the &lt;code&gt;Promise&lt;/code&gt;, and,
when &lt;code&gt;resolve&lt;/code&gt; is called, we "unblock" and resume running &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But.. what happens if there's a bug in the &lt;code&gt;do some work&lt;/code&gt;, and we don't
call &lt;code&gt;resolve&lt;/code&gt;?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;async function main() {
  const made = await new Promise((resolve, reject) =&amp;gt; {
    // (there's like four different bugs here)
    switch (Math.random(2)) {
      case 0:
        resolve(2);
        break;
      case 1:
        resolve(3);
        break;
    }
  });
  return made + 3;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;% node a.js
%
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...the app just vanishes. Our &lt;code&gt;then()&lt;/code&gt;, &lt;code&gt;catch()&lt;/code&gt;, and &lt;code&gt;finally()&lt;/code&gt; are
not run. The rest of &lt;code&gt;main&lt;/code&gt; isn't run either. The exit status is &lt;code&gt;SUCCESS&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As far as &lt;code&gt;node&lt;/code&gt; is concerned, there is no code to run, and no IO is
outstanding, so it's done. Bye!&lt;/p&gt;
&lt;p&gt;Note that this can happen &lt;em&gt;anywhere&lt;/em&gt; in your entire application. Deep within
some library, on handling input, or only under certain load conditions.&lt;/p&gt;
&lt;p&gt;Nobody would write code like that, you'd think. Unfortunately, much of the
ecosystem forces you to write code like this; it's pretty much the only
reason remaining you would write explicit promises. For example,
&lt;a href="https://github.com/FauxFaux/spooky-exit/blob/1cffd48509fca1b6376e9fede7945bc05107f37d/index.js#L4"&gt;dealing with subprocesses&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;await new Promise((resolve, reject) =&amp;gt; {
  child.once('exit', () =&amp;gt; resolve());
  child.once('error', () =&amp;gt; reject());
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What happens if neither of these events fires? Your app is gone.&lt;/p&gt;
&lt;p&gt;I hit this all the time. &lt;code&gt;unzipper&lt;/code&gt; took down a service at work occasionally,
probably &lt;a href="https://github.com/ZJONSSON/node-unzipper/pull/137"&gt;this similar IO issue&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I hit the
&lt;a href="https://github.com/FauxFaux/gh-health/blob/9de40bb84467cadc239e5783ec65a0227e734339/lib/hefty/git.ts#L6"&gt;subprocess issue using the library in the simplest way I can imagine&lt;/a&gt;,
reading the output of a command, then waiting for it to exit. Popular wrapper
libraries &lt;a href="https://github.com/rauschma/stringio/blob/0617012942e9731aafd9e0eb70a2e3aed1ff4398/ts/src/index.ts#L130"&gt;have pretty much the same code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The solution?&lt;/p&gt;
&lt;p&gt;After consulting with &lt;a href="http://james-ross.co.uk/"&gt;a serious expert&lt;/a&gt;, we decided
that the events probably don't fire (sometimes, under load) if they are
not registered when the event happens. You might expect this, I didn't.
You can resolve this by
&lt;a href="https://github.com/FauxFaux/spooky-exit/blob/6b85c4effc7add19b760252d05eee5c89aa7c00e/index.js#L16"&gt;moving the promise creation above other code, and &lt;code&gt;await&lt;/code&gt;ing it later&lt;/a&gt;.
This relies on the (surprising to me!) execution order of &lt;code&gt;Promise&lt;/code&gt; constructor
arguments.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;You can also have great fun looking at execution order in your test case.&lt;/p&gt;
&lt;p&gt;&lt;img src="/files/spooky-exit-flow.png"/&gt;&lt;/p&gt;
&lt;p&gt;A row (in this picture, normally a column) is a job, which works from &lt;code&gt;1e&lt;/code&gt;nter,
to &lt;code&gt;8a&lt;/code&gt;waited.&lt;/p&gt;
&lt;p&gt;This recording shows all of the workers completing the read in a row (&lt;code&gt;6c&lt;/code&gt;),
then interleaving of the function completing (&lt;code&gt;7x&lt;/code&gt;, &lt;code&gt;8a&lt;/code&gt;), with new workers
starting (&lt;code&gt;1e&lt;/code&gt;, etc.). Note how some of the jobs &lt;code&gt;7x&lt;/code&gt; (exit) before they
&lt;code&gt;6c&lt;/code&gt; (complete reading), which is probably our bug.&lt;/p&gt;</content><link href="https://blog.goeswhere.com/2019/10/spooky-exit/"/><published>2026-02-22T14:38:53.387404+00:00</published></entry><entry><id>https://blog.goeswhere.com/2026/02/quooker-cube/</id><title>Failed Quooker Cube</title><updated>2026-02-22T14:51:47.395538+00:00</updated><content>&lt;p&gt;I received a failed Quooker Cube chiller unit.&lt;/p&gt;
&lt;p&gt;Upon connection to power, nothing would happen; no lights, no sounds.&lt;/p&gt;
&lt;p&gt;Slightly weird board layout, with the main voltage conversion "primary"
situated a significant distance from the mains input "power supply":&lt;/p&gt;
&lt;p&gt;&lt;img src="/files/quooker-cube-board.jpg"/&gt;&lt;/p&gt;
&lt;p&gt;Investigation revealed the voltage on the secondary capacitors was only
around one volt. The rectification diodes test fine.&lt;/p&gt;
&lt;p&gt;Investigating the feedback circuit, I noticed that the diode in red is
short circuit; 0 Ohm in both directions. Verified out of circuit.&lt;/p&gt;
&lt;p&gt;I believe this is D5 for the &lt;a href="https://www.diodes.com/datasheet/download/AP3983R.pdf"&gt;AP3983R&lt;/a&gt;,
acting as the main power supply for the chip, from the feedback winding,
after R1/R2 provide the bootstrap.&lt;/p&gt;
&lt;p&gt;By failing, it's pulling the feedback pin high, resulting in limited switching?&lt;/p&gt;
&lt;p&gt;&lt;img src="/files/quooker-circuit.png"/&gt;&lt;/p&gt;
&lt;p&gt;Removing the diode appears to have improved matters, but I await a replacement
before claiming a full fix.&lt;/p&gt;</content><link href="https://blog.goeswhere.com/2026/02/quooker-cube/"/><published>2026-02-22T14:51:47.395538+00:00</published></entry></feed>