Expand description
Reading wsl.exe --list --verbose, and deciding that a name an operator
typed is exactly one distribution that is really installed.
§wsl.exe answers in UTF-16, and sometimes does not
Microsoft documents wsl --list --verbose as the way to enumerate
installed distributions and versions
(https://learn.microsoft.com/en-us/windows/wsl/basic-commands). What it
does not document is the encoding, and it has changed: for most of WSL’s
life the output has been UTF-16 little-endian — which through a redirected
pipe reads as ASCII interleaved with NUL bytes — and newer builds have
started emitting plain UTF-8 for some subcommands. A parser that assumes
either one is a parser that reports “no distributions are installed” on the
other, which is the worst possible failure here: it looks exactly like a
machine with no WSL, and the remedy it suggests is to install one.
So decode_console_output decides per call, from the bytes:
| Signal | Read as |
|---|---|
FF FE byte-order mark | UTF-16LE |
EF BB BF byte-order mark | UTF-8 |
| even length, and most odd-indexed bytes are NUL | UTF-16LE |
| anything else | UTF-8 |
The byte-order mark is authoritative and is checked first. The NUL
heuristic exists for the BOM-less UTF-16 that a redirected wsl.exe
produces, and it is deliberately a majority test rather than an “any NUL”
test, so that a distribution name in Cyrillic or Japanese — whose UTF-16
high bytes are not NUL — is still recognised as UTF-16 on the strength of
the ASCII around it.
Anything that does not decode cleanly is kept, with the replacement
character, and DecodedOutput::is_lossy says so. Nothing here silently
repairs a name: a row whose name did not survive decoding is moved to
DistributionTable::unreadable rather than offered as something an
operator may install into.
§A name may contain spaces, so the table is parsed from the right
NAME STATE VERSION
* Ubuntu Running 2
Debian GNU/Linux 12 Stopped 1split_whitespace would turn the third row’s name into four fields. The
last two columns, however, are a single word each, so the row is cut from
the end: the last token is the version, the one before it is the state, and
everything left — trimmed — is the name, spaces, punctuation and all. The
header row falls out of the same rule for free, because VERSION does not
parse as a number.
Structs§
- Decoded
Output - Console output, decoded, and how it had to be read.
- Distribution
Table - Everything
wsl --list --verbosereported, and everything it reported that could not be read. - Installed
Distribution - One row of
wsl --list --verbose.
Enums§
- Console
Encoding - How
decode_console_outputread the bytes.
Constants§
- MAX_
DISTRIBUTION_ NAME - The longest distribution name this adapter will handle.
Functions§
- decode_
console_ output - Decodes what a Windows console program wrote to a pipe.
- validate_
distribution_ name - Checks a name’s syntax, before it is ever put in an argument vector.