<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>VulpineCitrus - Blog</title>
    <subtitle>Personal blog of a compsci student interested in networking, programming, and bicycles.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://vulpinecitrus.info/blog/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-03-19T00:00:00+00:00</updated>
    <id>https://vulpinecitrus.info/blog/atom.xml</id>
    <entry xml:lang="en">
        <title>Diving into Radio Listening: POCSAG, Alphapage, and how i taught myself some GNURadio</title>
        <published>2026-02-22T00:00:00+00:00</published>
        <updated>2026-02-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/rf-pocsag-alphapage-gnuradio/"/>
        <id>https://vulpinecitrus.info/blog/rf-pocsag-alphapage-gnuradio/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/rf-pocsag-alphapage-gnuradio/">&lt;p&gt;Pagers used to be all the rage in the late 80s, 90s and early 2000s. You could
carry around a little battery-powered trinket that could ring and give you a
little text message. How neat! Then, mobile telephones became easier and easier to
carry around, then smartphones became a thing, and pagers died.&lt;&#x2F;p&gt;
&lt;p&gt;Pagers worked and still work via radio signals. A lot of different radio
standards for pagers have been developed over the decades, but, here, i will
focus on the &lt;em&gt;POCSAG&lt;&#x2F;em&gt; family of standards and how they were (and are) used here,
in France.&lt;&#x2F;p&gt;
&lt;p&gt;I will go over three different things in this post: a tiny bit of history on the
Alphapage paging network in France, some technical information about POCSAG, and
how i tweaked a GNURadio script to do multi-channel decoding to capture multiple
channels at the same time.&lt;&#x2F;p&gt;
&lt;p&gt;Why am i writing an english-speaking article on a blog primarily oriented towards an english-speaking audience with so much french-specific data?
Well, for one, i only live in one country, and i haven’t had as much experienced
listening in on the data of other countries. If you want the full french experience,
&lt;a href=&quot;&#x2F;fr&#x2F;blog&#x2F;rf-pagers-pocsag&quot;&gt;you can also read this in french&lt;&#x2F;a&gt; when i get around to translating it (soon (hopefully)).&lt;&#x2F;p&gt;
&lt;h1 id=&quot;A_Brief_History_of_Alphapage&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#A_Brief_History_of_Alphapage&quot; aria-label=&quot;Anchor link for: A_Brief_History_of_Alphapage&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
A Brief History of Alphapage&lt;&#x2F;h1&gt;
&lt;p&gt;A &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.mobilophiles.com&#x2F;article-la-collection-avec-les-sms-alphapage-eurosignal-avec-tatoo-tamtam-119795644.html&quot;&gt;lot of companies&lt;&#x2F;a&gt; used to sell pager services for French consumers
(&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;tatoo.fr&#x2F;&quot;&gt;Tatoo&lt;&#x2F;a&gt;, Tam-Tam and Kobby; the latter two of which used
FLEX and relied on separate networks) and companies (Alphapage). These devices
are not necessarily junk today! Tatoo, in particular, was the
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mediatheque-numerique.loire.fr&#x2F;concept?id=83c51533-b88b-4c29-8e8d-7f5dd8ec77ed&quot;&gt;consumer-brand&lt;&#x2F;a&gt;
of the network i will focus on today. Some people have &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lafibre.info&#x2F;histoire&#x2F;radiomessagerie-tatoo-ou-lanti-5g&#x2F;&quot;&gt;tried to and succeeded
in&lt;&#x2F;a&gt;
broadcasting to a Tatoo pager they bought online or found stashed in a drawer.
The cost, however, is prohibitive (more than 3.5€ per message). Unless you’re
modding some hardware for a ham system like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;hampager.de&#x2F;#&#x2F;&quot;&gt;DAPNet&lt;&#x2F;a&gt;,
it’s unrealistic to try and build on top of a system that sends data to pagers.&lt;&#x2F;p&gt;
&lt;p&gt;The reason i focus specifically on Alphapage is because, contrary to the other
networks at the time, Alphapage is &lt;em&gt;still&lt;&#x2F;em&gt; operational, albeit under a
different name with a different company owning it. There are still messages
being broadcast to POCSAG-capable pagers today.&lt;&#x2F;p&gt;
&lt;p&gt;Alphapage’s infrastructure used to belong to &lt;em&gt;France Télécom&lt;&#x2F;em&gt;, the name of our former
national telecom operator. Their commercial network,
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;fr.wikipedia.org&#x2F;wiki&#x2F;Alphapage&quot;&gt;Alphapage&lt;&#x2F;a&gt;, was broken off as property
of a company that was bought and renamed &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.emessage.fr&#x2F;&quot;&gt;&lt;em&gt;e*Message
France&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; when France Télécom was dismantled and sold
to the private sector. That company officially received the right to operate
FT’s pager frequencies in 2001, with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.legifrance.gouv.fr&#x2F;jorf&#x2F;id&#x2F;JORFTEXT000000392102&quot;&gt;ARCEP decision #2001-308 of March 23rd
2001&lt;&#x2F;a&gt;.
That decision conveniently lists the frequencies and some technical information.
Around 466~MHz, five 25 kHz channels are listed:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Channel 1 : 466.02500 MHz&lt;&#x2F;li&gt;
&lt;li&gt;Channel 2 : 466.05000 MHz&lt;&#x2F;li&gt;
&lt;li&gt;Channel 3 : 466.07500 MHz&lt;&#x2F;li&gt;
&lt;li&gt;Channel 7 : 466.17500 MHz&lt;&#x2F;li&gt;
&lt;li&gt;Channel 8 : 466.20625 MHz&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;e*Message is still authorized to use these frequencies in all of France. Another
frequency, 87.390 MHz is listed, but not currently used. In fact, as of
September 2025, only channels 2, 7 and 8 are still in use by e*Message. This is
coherent with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.arcep.fr&#x2F;uploads&#x2F;tx_gsavis&#x2F;25-0694.pdf&quot;&gt;various ARCEP decisions&lt;&#x2F;a&gt; i found
that list the channels still in use as 2, 7 and 8. Those channels are usable, as
of my writing this, until December 31st 2030.&lt;&#x2F;p&gt;
&lt;p&gt;By the mid-90s, the coverage of Alphapage was &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.histelfrance.fr&#x2F;radiomessageriesunilaterales&#x2F;&quot;&gt;rather
impressive&lt;&#x2F;a&gt;. By 2007,
e*Message itself advertised &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20250513123718&#x2F;https:&#x2F;&#x2F;www.hellopro.fr&#x2F;documentation&#x2F;doc_societe&#x2F;148309_6247b3f2f19650bb4a3d2dff9ee4e417.pdf&quot;&gt;“about 500 antennas spread all over the country”&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In several places online, i read that France was cut in distinctive zones
depending on your geographic location, and that Alphapage-compatible pagers
were registered to a specific zone. However, i was never able to find a proper
map of those zones, nor confirm that that was ever the case.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;The_POCSAG_Protocol&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#The_POCSAG_Protocol&quot; aria-label=&quot;Anchor link for: The_POCSAG_Protocol&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
The POCSAG Protocol&lt;&#x2F;h1&gt;
&lt;p&gt;The standard used by these Alphapage-compatible pagers is the &lt;em&gt;Radio-Paging Code No. 1&lt;&#x2F;em&gt; of the
&lt;strong&gt;P&lt;&#x2F;strong&gt;ost &lt;strong&gt;O&lt;&#x2F;strong&gt;ffice &lt;strong&gt;C&lt;&#x2F;strong&gt;ode &lt;strong&gt;S&lt;&#x2F;strong&gt;tandardization &lt;strong&gt;A&lt;&#x2F;strong&gt;dvisory &lt;strong&gt;G&lt;&#x2F;strong&gt;roup, or POCSAG.
POCSAG was formed in 1976 by a group of international engineers looking to develop a wide-area paging code.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.raveon.com&#x2F;pdfiles&#x2F;AN142%28POCSAG%29.pdf&quot;&gt;POCSAG&lt;&#x2F;a&gt; (the protocol, not the standards group) supports different bitrates: 512, 1200 and 2400 bps.
POCSAG transmissions begin with a preamble of 576 bits that alternate between 0 and 1.
Most pagers put themselves to sleep to save power, and wake up to listen for a preamble at a regular interval (small enough that they will catch an interval when one occurs).
The preamble signals for pagers to stay awake and power up decoding hardware. It also helps identify the
data rate that will be used.&lt;&#x2F;p&gt;
&lt;p&gt;The rest of the communication comes in &lt;em&gt;batches&lt;&#x2F;em&gt;. POCSAG is capable of delivering messages simultaneously to multiple units
by dividing messages into piece that are transmitted progressively batch per batch.
Each batch is time-divided into 8 frames (preceded by a magic sequence of bytes called the Frame Synchronization Code).
Then, each frame is divided into two codeword slots, making it 16 codewords per batches.
Each codeword can contain either an address (first bit is 0), or a piece of message (first bit set to 1).&lt;&#x2F;p&gt;
&lt;p&gt;Where a message is in each batch will partially determine who is receiving it.
In POCSAG, a pager’s address is 21 bits long: 18 bits are transmitted in the
address codeword, and the last 3 are derived from the position of the codeword
in the batch. That neat little trick saves space and time in transmission! When
a batch transmits an address at a given codeword position, the same codeword
position in incoming batches will contain the pieces of the incoming message.
The pager will keep receiving and decoding its message until an address or idle
codeword is transmitted in the codeword slot that it was listening for. Idle
codewords are used when no message is to be transmitted in a given codeword
slot.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           +-----------+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           | B |   | B |     +---+-------------------------------+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           | A |   | A |     |   | 8 |   | F | R | A | M | E | S |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           | T | . | T |     | F +   +   +   +   +   +   +   +   +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+-- SYNC --+ C | . | C |     | C |C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           | H | . | H =====&amp;gt;| S |0|0|0|0|0|0|0|0|0|1|1|1|1|1|1|1|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           |   |   |   |     |   |1|2|3|4|5|6|7|8|9|0|1|2|3|4|5|6|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           | 1 |   | n |     +---+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           +-----------+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;POCSAG messages can be decoded in multiple modes:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;BCD (Binary-Coded Decimal) aka “Numeric”: Only digits, parens, dashes, ‘*’ and some special control characters are sent&lt;&#x2F;li&gt;
&lt;li&gt;Alphanumeric with 7-bit ASCII, transmitted in little-endian.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Of note is that only 20 bits can be transmitted at a time in a codeword. Thus,
when your characters are 7-bit, there will almost always be one last codeword
filled with a bit, and then null&#x2F;termination characters. Per the standard,
the NULL character is the only one that is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.raveon.com&#x2F;pdfiles&#x2F;AN142%28POCSAG%29.pdf&quot;&gt;allowed to be truncated&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Actually_Listening_to_POCSAG&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Actually_Listening_to_POCSAG&quot; aria-label=&quot;Anchor link for: Actually_Listening_to_POCSAG&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Actually Listening to POCSAG&lt;&#x2F;h1&gt;
&lt;p&gt;The technical stack used to decode and see pager messages is
not that complicated, and has been &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;blog.f8asb.com&#x2F;2024&#x2F;06&#x2F;30&#x2F;decodage-pocsag-en-ligne-de-commande-sous-linux&#x2F;&quot;&gt;tried and tested&lt;&#x2F;a&gt; before. &lt;code&gt;multimon-ng&lt;&#x2F;code&gt; is a CLI tool that provides decoding for a
lot of paging protocols, including POCSAG. You just need to feed it raw audio
at a bandwidth of 22.050K, and it’ll happily decode for you.&lt;&#x2F;p&gt;
&lt;p&gt;So i simply ran the same kind of command that people recommend for Alphapage: &lt;code&gt;rtl_fm&lt;&#x2F;code&gt; piped into &lt;code&gt;multimon-ng&lt;&#x2F;code&gt;. I looked at the three frequencies still in use
on SDR++ and figured out that, roughly every minute, a message is sent on all three frequencies.
Channel 7 received more frequent messages. So i picked that frequency:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rtl_fm -p -5 -F 0 -E dc -M fm -T -g 32 -f 466.175M -s 22050 | multimon-ng -t raw -c -a POCSAG1200 --timestamp -&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And eventually, it decodes things! Most of it is junk i can’t understand, all of it is stuff i cannot share anyways&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-legal-1&quot;&gt;&lt;a href=&quot;#fn-legal&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, but something is coming through.&lt;&#x2F;p&gt;
&lt;p&gt;Because a pager only listens to one of the
specific carriers, and i had no way to simultaneously monitor messages sent to
the three channels, i figured “well, my RTL-SDR dongle can cover the bandwidth
needed to include all three channels, surely it isn’t too hard to decode all
three channels at the same time”. That sounded like a fun technical challenge.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;rtl_fm&lt;&#x2F;code&gt; is a very nifty piece of CLI tooling if you want to just listen to one
frequency, or multiple frequencies with some scanning logic. Problem is, no
matter how i tuned the squelch, &lt;code&gt;rtl_fm&lt;&#x2F;code&gt; would get stuck on one channel and stop
scanning. Sometimes, i would see two carriers active, but &lt;code&gt;rtl_fm&lt;&#x2F;code&gt; can only tune
to one frequency at a time, and &lt;code&gt;multimon-ng&lt;&#x2F;code&gt; cannot know which frequency is
being listened and print it (another piece of information i want). Worse, when
a channel would become active, &lt;code&gt;rtl_fm&lt;&#x2F;code&gt; would switch to it after the
synchronization sequence started: &lt;code&gt;multimon-ng&lt;&#x2F;code&gt; couldn’t decode that audio.&lt;&#x2F;p&gt;
&lt;p&gt;So i poked around the internet, figuring that “someone more competent might
already have done that”, and i found &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;EliasOenal&#x2F;multimon-ng&#x2F;issues&#x2F;165&quot;&gt;&lt;code&gt;multimon-ng&lt;&#x2F;code&gt; issue #165&lt;&#x2F;a&gt;.
In the &lt;code&gt;examples&#x2F;&lt;&#x2F;code&gt; folder of the &lt;code&gt;multimon-ng&lt;&#x2F;code&gt; repository, there is an example
Python script called &lt;code&gt;multipager.py&lt;&#x2F;code&gt; generated with GNURadio Companion that
splits received data into a bunch of channels and decodes them all individually
by piping the output audio to one &lt;code&gt;multimon-ng&lt;&#x2F;code&gt; process per channel. The output
is then &lt;em&gt;parsed&lt;&#x2F;em&gt; (yes, that’s awful) and the script adds information such as
the frequency where a message was decoded.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;So_What_is_this_GNU_of_the_Radio_Anyways&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#So_What_is_this_GNU_of_the_Radio_Anyways&quot; aria-label=&quot;Anchor link for: So_What_is_this_GNU_of_the_Radio_Anyways&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
So What is this GNU of the Radio Anyways&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gnuradio.org&quot;&gt;GNURadio&lt;&#x2F;a&gt; is a flow-based framework to develop digital signal processing
applications. It works on a logic of linking sources to sinks through a bunch of
filters and transformations of the input. In the script above, we use the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;osmocom.org&#x2F;&quot;&gt;Open Source
Mobile Communication (OSMoCom)&lt;&#x2F;a&gt; library to have access to SDR peripherals.&lt;&#x2F;p&gt;
&lt;p&gt;GNURadio comes with a piece of software called &lt;em&gt;GNURadio Companion&lt;&#x2F;em&gt; (GRC) that provides
the graphical view of these processing flowcharts. As a bonus, once a flowchart
is validated in GRC, it can be exported as a Python script that uses the Python
&lt;code&gt;gnuradio&lt;&#x2F;code&gt; library.&lt;&#x2F;p&gt;
&lt;p&gt;And that’s where &lt;code&gt;multimon-ng&lt;&#x2F;code&gt;’s multipager is an issue: it was generated for
Python2, on an old version of GRC. Some bindings are not located in the same
namespaces anymore, some libraries have stopped existing, and the language as a
whole is very different.&lt;&#x2F;p&gt;
&lt;p&gt;At first, i simply updated the script. It’s not the first time i update a Python 2
script for Python 3. Even replacing some libraries, notably for async I&#x2F;O, was
done fairly quickly. And i could run the script rather fast.&lt;&#x2F;p&gt;
&lt;p&gt;But then i hit an issue: channelizing. With how the script was originally made,
the input bandwidth is divided into &lt;code&gt;n&lt;&#x2F;code&gt; equally sized channels. The Alphapage channels are not well
aligned for that: they do not &lt;em&gt;all&lt;&#x2F;em&gt; fit in &lt;code&gt;n&lt;&#x2F;code&gt; equally spaced channels because
of channel 8 (466.20625 MHz).&lt;&#x2F;p&gt;
&lt;p&gt;So i had to learn some digital signal processing.&lt;&#x2F;p&gt;
&lt;p&gt;What i want to do is have three copies of the baseband, cut down to the bandwidth
of POCSAG, and shifted such that the center frequency is correct for a given
channel.
In DSP, frequency translation, also abbreviated &lt;em&gt;Frequency XLating&lt;&#x2F;em&gt;, is a process by which an input
spectrum is &lt;em&gt;shifted&lt;&#x2F;em&gt; frequency-wise. In GNURadio, you can even use a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;wiki.gnuradio.org&#x2F;index.php?title=Frequency_Xlating_FIR_Filter&quot;&gt;&lt;em&gt;Finite
Impulse Response&lt;&#x2F;em&gt; implementation of frequency translation&lt;&#x2F;a&gt; to combine
translation of the spectrum and an application of filters to isolate a piece of
that band with the correct bandwidth. i don’t really understand any of the nitty-gritty underneath all of this, so i will let you
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Finite_Impulse_Response&quot;&gt;read the Wikipedia
page&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;So i went on my merry way hacking away at the script: i need to center the
frequency in the middle of all channels (so 466.128125 MHz) in such a way that if
there is a DC offset, if will not bother us. Then, i need to connect three
XLat IR filters to the output of the OSMoCom SDR source to shift to all three
active pocsag channels. Then, i just hook myself to the existing bits of the script
that demodulate the spectrum into audio and pipes it into &lt;code&gt;multimon-ng&lt;&#x2F;code&gt; and parses
the output.&lt;&#x2F;p&gt;
&lt;p&gt;And &lt;em&gt;voilà&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The actual script is available &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;Lymkwi&#x2F;radio-scripts&#x2F;src&#x2F;branch&#x2F;main&#x2F;pocsag&#x2F;alphapage-rx.py&quot;&gt;here&lt;&#x2F;a&gt;. You can pass it the same kinds of
arguments that &lt;code&gt;multipager.py&lt;&#x2F;code&gt; from the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;EliasOenal&#x2F;multimon-ng&#x2F;blob&#x2F;master&#x2F;example&#x2F;multipager.py&quot;&gt;original repository&lt;&#x2F;a&gt; takes, except &lt;code&gt;-f&lt;&#x2F;code&gt;
and &lt;code&gt;-c&lt;&#x2F;code&gt; (those are never queried).&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Where_To_Go_From_Here?&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Where_To_Go_From_Here?&quot; aria-label=&quot;Anchor link for: Where_To_Go_From_Here?&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Where To Go From Here?&lt;&#x2F;h1&gt;
&lt;p&gt;Pagers are a cool little tool to play with. Some people &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;toutetrien.lithio.fr&#x2F;article&#x2F;jai-un-bipeur&#x2F;&quot;&gt;send themselves messages&lt;&#x2F;a&gt;,
some others are trying to build entire &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;hampager.de&#x2F;&quot;&gt;networks for them&lt;&#x2F;a&gt;.
In the future, i might mess around with making a low-power local emitter for
POCSAG, to automate notifications or alarms for meds and calendar events.&lt;&#x2F;p&gt;
&lt;p&gt;In general, i find learning about technology that provides you with more off-grids
communication fascinating!&lt;&#x2F;p&gt;
&lt;!-- vim: set cc=80 tw=80 spell spelllang=en --&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-legal&quot;&gt;
&lt;p&gt;i’m pretty sure the precise piece of legislation
is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.legifrance.gouv.fr&#x2F;codes&#x2F;article_lc&#x2F;LEGIARTI000042193573&quot;&gt;Penal Code R226-15 ¶2&lt;&#x2F;a&gt;
for France. Be smart! don’t fedpost about what you hear on the radio if you weren’t
the intended recipient :) &lt;a href=&quot;#fr-legal-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>A Completely Innocuous Blog Post about vPMU in QEMU</title>
        <published>2026-02-10T00:00:00+00:00</published>
        <updated>2026-02-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/qemu-vpmu-heterogenous-cpu/"/>
        <id>https://vulpinecitrus.info/blog/qemu-vpmu-heterogenous-cpu/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/qemu-vpmu-heterogenous-cpu/">&lt;p&gt;Hey!&lt;&#x2F;p&gt;
&lt;p&gt;If like me, you spend a lot of time debugging the Linux kernel, especially with
the goal of modifying the performance of user programs, you may often find
yourself in the silly position where you need to run &lt;code&gt;perf&lt;&#x2F;code&gt; inside of a virtual
machine (typically run using &lt;code&gt;qemu&lt;&#x2F;code&gt;) in order to obtain hardware performance
counters.&lt;&#x2F;p&gt;
&lt;p&gt;In x86(_64) CPUs, the component responsible for providing you these pieces of
information is called the &lt;em&gt;Performance Monitoring Unit&lt;&#x2F;em&gt;, or PMU. Your kernel,
when it boots, figures out what brand and model your CPU is, and which PMU driver
will be responsible for handling initialization and gathering of information.&lt;&#x2F;p&gt;
&lt;p&gt;In a virtualized environment, however, the hypervisor is responsible for providing
a PMU to the guest! In QEMU, this is often done by enabling the KVM accelerator,
and copying the host topology, as such:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-enable-kvm -cpu host&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And with that, you can have a guest CPU with features such as:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Architecture:                    x86_64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CPU op-mode(s):                  32-bit, 64-bit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Address sizes:                   39 bits physical, 48 bits virtual&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Byte Order:                      Little Endian&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CPU(s):                          1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;On-line CPU(s) list:             0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Vendor ID:                       GenuineIntel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Model name:                      Intel(R) Core(TM) i7-6600U CPU @ 2.60GHz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CPU family:                      6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Model:                           78&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Thread(s) per core:              1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Core(s) per socket:              1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Socket(s):                       1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Stepping:                        3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BogoMIPS:                        5615.99&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Flags:                           fpu vme de [...] arch_perfmon [...]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Virtualization:                  VT-x&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Hypervisor vendor:               KVM&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Virtualization type:             full&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[...]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Which clearly shows &lt;code&gt;arch_perfmon&lt;&#x2F;code&gt; (the name of the x86 feature of hardware performance
monitoring in Intel CPU cores, especially in the p6 family starting after Yonah cores) enabled!&lt;&#x2F;p&gt;
&lt;p&gt;On AMD, the feature has a different name (&lt;code&gt;perfctr_core&lt;&#x2F;code&gt;), and will be handled by the &lt;code&gt;kvm-amd&lt;&#x2F;code&gt;
Linux kernel module.&lt;&#x2F;p&gt;
&lt;p&gt;And, yeah! Hope that helped.&lt;&#x2F;p&gt;
&lt;p style=&quot;margin-bottom: 18cm;&quot;&gt; &lt;&#x2F;p&gt;
&lt;p&gt;…&lt;&#x2F;p&gt;
&lt;p&gt;&lt;small&gt;still here?&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;p style=&quot;margin-bottom: 10cm;&quot;&gt; &lt;&#x2F;p&gt;
&lt;p&gt;…&lt;&#x2F;p&gt;
&lt;p&gt;&lt;small&gt;good.&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;p style=&quot;margin-bottom: 20cm;&quot;&gt; &lt;&#x2F;p&gt;
&lt;p&gt;Look, i would not know what a vPMU is, what p6-family Intel cores have
hardware-backed PMUs, nor how KVM plays a role in exposing those to the guest,
if i had managed to make it all work as easily as all online documentation
seems to imply.&lt;&#x2F;p&gt;
&lt;p&gt;This is a story about debugging, and bad development practices, and pain.&lt;&#x2F;p&gt;
&lt;p&gt;Mostly pain.&lt;&#x2F;p&gt;
&lt;p&gt;This is a blog post about how a single &lt;code&gt;if&lt;&#x2F;code&gt; statement guarding a code block
with no warning log, made me lose a whole day of work investigating a potential
bug.&lt;&#x2F;p&gt;
&lt;p style=&quot;margin-bottom: 20cm;&quot;&gt; &lt;&#x2F;p&gt;
&lt;h1 class=&quot;glitch-text-hover&quot;&gt;This is a Blog Post About What Happens When You Fall Through the Cracks of People&#x27;s Assumptions&lt;&#x2F;h1&gt;
&lt;br&gt;
&lt;hr&gt;
&lt;br&gt;
&lt;h2 id=&quot;Part_1:_This_is_the_Part_Where_i_Still_Sound_Somewhat_Sane&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Part_1:_This_is_the_Part_Where_i_Still_Sound_Somewhat_Sane&quot; aria-label=&quot;Anchor link for: Part_1:_This_is_the_Part_Where_i_Still_Sound_Somewhat_Sane&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Part 1: This is the Part Where i Still Sound Somewhat Sane&lt;&#x2F;h2&gt;
&lt;p&gt;The reason you don’t read my yapping about Linux as much these days is that most
of the Linux-touching i do is actually for work. On a rare occasion, i happen
upon a tangential problem posed, for example, by a benchmark setup problem. Even
more rarely, that problem becomes a time sink hole that engulfs an entire day of
my own time, and brings to light an interesting problem that will almost
definitely trip other people in the future.&lt;&#x2F;p&gt;
&lt;p&gt;And so, i feel compelled to write about it.&lt;&#x2F;p&gt;
&lt;p&gt;The story of today brings us to QEMU, KVM, and early CPU feature recognition.&lt;&#x2F;p&gt;
&lt;p&gt;For complicated reasons, I needed to sample some hardware performance counters
from within a QEMU instance running my own build of the Linux kernel. My first
thought went along the lines of “&lt;em&gt;oh well, i might need a &lt;code&gt;perf&lt;&#x2F;code&gt; binary compiled
for my custom kernel, let me do that&lt;&#x2F;em&gt;”, and i happily tweaked build scripts to
install the binary.&lt;&#x2F;p&gt;
&lt;p&gt;Running it, i got:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;~ # perf stat -d echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;event syntax error: &amp;#39;cpu_core&#x2F;TOPDOWN.SLOTS,metric-id=cpu_core!3TOPDOWN.SLOTS!3&#x2F;,cpu_core&#x2F;topdown-retiring,metric-id=cpu_core!3topdown!1retiring!3&#x2F;,cpu_atom&#x2F;TOPDOWN_RETIRING.ALL,metric-id=cpu_atom!3TOPDOWN_RETIRING.ALL!3&#x2F;,cpu_core&#x2F;topdown-bad-spec,metric-id=cpu_core!3t..&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                     \___ Bad event or PMU&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Unable to find PMU or event on a PMU of &amp;#39;cpu_core&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Performance counter stats for &amp;#39;echo&amp;#39;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;              0.45 msec task-clock               #    0.215 CPUs utilized&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                 1      context-switches         #    2.231 K&#x2F;sec&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                 0      cpu-migrations           #    0.000 &#x2F;sec&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                60      page-faults              #  133.875 K&#x2F;sec&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &amp;lt;not supported&amp;gt;      cycles&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &amp;lt;not supported&amp;gt;      instructions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &amp;lt;not supported&amp;gt;      branches&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &amp;lt;not supported&amp;gt;      branch-misses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &amp;lt;not supported&amp;gt;      L1-dcache-loads&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &amp;lt;not supported&amp;gt;      L1-dcache-load-misses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &amp;lt;not supported&amp;gt;      LLC-loads&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &amp;lt;not supported&amp;gt;      LLC-load-misses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       0.002081276 seconds time elapsed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       0.000392000 seconds user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       0.000392000 seconds sys&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That’s odd. Okay, maybe hardware counters from within a VM is a bit weirder.&lt;&#x2F;p&gt;
&lt;p&gt;i then spend about five minutes searching online a combination of the words
&lt;code&gt;qemu&lt;&#x2F;code&gt;, &lt;code&gt;perf&lt;&#x2F;code&gt;, and &lt;code&gt;hardware counters&lt;&#x2F;code&gt;. Eventually, the
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;chpresearch.wordpress.com&#x2F;2021&#x2F;05&#x2F;19&#x2F;enabling-vpmu-on-guest-vms-kvm&#x2F;&quot;&gt;answers&lt;&#x2F;a&gt;
i
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20251119200754&#x2F;https:&#x2F;&#x2F;docs.redhat.com&#x2F;en&#x2F;documentation&#x2F;red_hat_enterprise_linux&#x2F;7&#x2F;html&#x2F;virtualization_tuning_and_optimization_guide&#x2F;sect-virtualization_tuning_optimization_guide-monitoring_tools-vpmu&quot;&gt;find&lt;&#x2F;a&gt;
in
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;kvm.vger.kernel.narkive.com&#x2F;HtK5hlCP&#x2F;how-to-know-that-vpmu-is-enabled-or-disabled&quot;&gt;various&lt;&#x2F;a&gt;
places tell me that the feature i am looking for is called “Virtualized
Performance Monitoring Unit”, or “Virtualized PMU”, or “vPMU”. They also tell
me the same information i relayed at the top of the post:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Enabling vPMU in QEMU is done by enabling KVM and copying the host CPU
information: &lt;code&gt;-enable-kvm -cpu host&lt;&#x2F;code&gt; .&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;So i tried.&lt;&#x2F;p&gt;
&lt;p&gt;And it didn’t work. It. Didn’t. Work. Nothing changed. What was going on? Why
was i falling into a case that was documented nowhere? Oh no, it’s happening
again isn’t it, oh NO, NOT AGAI-&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Part_2:_My_Sanity_Slowly_Drains_as_I_Skim_DMesg_and_Kernel_Code&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Part_2:_My_Sanity_Slowly_Drains_as_I_Skim_DMesg_and_Kernel_Code&quot; aria-label=&quot;Anchor link for: Part_2:_My_Sanity_Slowly_Drains_as_I_Skim_DMesg_and_Kernel_Code&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Part 2: My Sanity Slowly Drains as I Skim DMesg and Kernel Code&lt;&#x2F;h2&gt;
&lt;p&gt;In order to start debugging, i had to figure out what was happening in the
kernel. For those who don’t know, &lt;code&gt;perf&lt;&#x2F;code&gt; interacts with an entire subsystem in
the Linux kernel (the &lt;code&gt;perf&lt;&#x2F;code&gt; subsystem) to retrieve hardware events. Thus, if
there was a bit of software that should know about the problems with the PMU, it
should be the kernel.&lt;&#x2F;p&gt;
&lt;p&gt;Running &lt;code&gt;dmesg | grep -i perf&lt;&#x2F;code&gt; i got the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[    0.133409] Performance Events: unsupported p6 CPU model 183 no PMU driver, software events only.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Oh, wait. So my CPU is not supported? Why? My kernel is a bit old (6.12), and my
CPU is, as you can guess, a Raptorlake (13th gen Intel, heterogeneous
architecture with Raptorcove performance cores, and Enhanced Gracemont
efficiency cores). Maybe there was a driver missing which was not in older Linux
versions? That’s what i thought, until i also ran a Linux 6.18 build and
obtained the same result.&lt;&#x2F;p&gt;
&lt;p&gt;On Linux v6.12, i hit &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.12&#x2F;source&#x2F;arch&#x2F;x86&#x2F;events&#x2F;intel&#x2F;p6.c#L272&quot;&gt;this line&lt;&#x2F;a&gt; (&lt;code&gt;arch&#x2F;x86&#x2F;events&#x2F;intel&#x2F;p6.c#L272&lt;&#x2F;code&gt;) in the following code:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;__init &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; p6_pmu_init&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    x86_pmu &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; p6_pmu;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    switch&lt;&#x2F;span&gt;&lt;span&gt; (boot_cpu_data.x86_model) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    case&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  1&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; &#x2F;* Pentium Pro *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        x86_add_quirk&lt;&#x2F;span&gt;&lt;span&gt;(p6_pmu_rdpmc_quirk);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        break&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    case&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  3&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; &#x2F;* Pentium II - Klamath *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    case&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  5&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; &#x2F;* Pentium II - Deschutes *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    case&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  6&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; &#x2F;* Pentium II - Mendocino *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        break&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    case&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  7&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; &#x2F;* Pentium III - Katmai *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    case&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  8&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; &#x2F;* Pentium III - Coppermine *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    case&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 10&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; &#x2F;* Pentium III Xeon *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    case&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 11&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; &#x2F;* Pentium III - Tualatin *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        break&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    case&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  9&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; &#x2F;* Pentium M - Banias *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    case&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 13&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; &#x2F;* Pentium M - Dothan *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        break&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    default&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        pr_cont&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;unsupported p6 CPU model &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, boot_cpu_data.x86_model);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        return -&lt;&#x2F;span&gt;&lt;span&gt;ENODEV;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    memcpy&lt;&#x2F;span&gt;&lt;span&gt;(hw_cache_event_ids, p6_hw_cache_event_ids,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        sizeof&lt;&#x2F;span&gt;&lt;span&gt;(hw_cache_event_ids));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That code initially had me guess that something about models not listed here
made them incompatible with vPMU. Maybe only older versions of p6 CPUs could
have virtualized PMUs? No.&lt;&#x2F;p&gt;
&lt;p&gt;Looking at v6.18, that function changed dramatically:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;__init &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; p6_pmu_init&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    x86_pmu &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; p6_pmu;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; (boot_cpu_data.x86_vfm&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span&gt; INTEL_PENTIUM_PRO)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        x86_add_quirk&lt;&#x2F;span&gt;&lt;span&gt;(p6_pmu_rdpmc_quirk);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    memcpy&lt;&#x2F;span&gt;&lt;span&gt;(hw_cache_event_ids, p6_hw_cache_event_ids,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        sizeof&lt;&#x2F;span&gt;&lt;span&gt;(hw_cache_event_ids));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And the new line i hit is located in the v6.18 version of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.18&#x2F;source&#x2F;arch&#x2F;x86&#x2F;events&#x2F;intel&#x2F;core.c&quot;&gt;&lt;code&gt;intel_pmu_init&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;__init &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; intel_pmu_init&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;* Architectural Perfmon was introduced starting with Core &amp;quot;Yonah&amp;quot; *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cpu_has&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        switch&lt;&#x2F;span&gt;&lt;span&gt; (boot_cpu_data.x86) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        case&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  6&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            if&lt;&#x2F;span&gt;&lt;span&gt; (boot_cpu_data.x86_vfm &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt; INTEL_CORE_YONAH)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;                return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; p6_pmu_init&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            break&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        case&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 11&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; knc_pmu_init&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        case&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 15&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; p4_pmu_init&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        pr_cont&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;unsupported CPU family &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; model &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            boot_cpu_data.x86, boot_cpu_data.x86_model);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        return -&lt;&#x2F;span&gt;&lt;span&gt;ENODEV;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So, “Architecture Perfmon was introduced starting with Core Yonah”, huh? This
bit of code seems to be responsible for initializing support for the PMU on an
Intel CPU at boot. i skipped the variable declarations, because the first bit of
code in that function is a check for CPU capabilities on the CPU the kernel
booted on. Specifically, we’re looking for an x86 feature called &lt;code&gt;arch_perfmon&lt;&#x2F;code&gt;.
If that feature is absent, we &lt;em&gt;then&lt;&#x2F;em&gt; call the &lt;code&gt;p6_pmu_init&lt;&#x2F;code&gt; function that
previously spewed the error log. The new organization of these functions clears
up the earlier confusion: &lt;code&gt;p6_pmu_init&lt;&#x2F;code&gt; is only run for pre-Yonah p6 family
cores in order to try and initialize the feature if it wasn’t already available.
Failing that (and it will! Even if you comment out the core version check), we
run into our &lt;code&gt;pr_cont&lt;&#x2F;code&gt; right there above, and return &lt;code&gt;-ENODEV&lt;&#x2F;code&gt;. Oops.&lt;&#x2F;p&gt;
&lt;p&gt;If you’re on an Intel CPU and run &lt;code&gt;lscpu&lt;&#x2F;code&gt;, you may find &lt;code&gt;arch_perfmon&lt;&#x2F;code&gt; in the
list of &lt;code&gt;Flags&lt;&#x2F;code&gt;. This signals that you have architectural support for your PMU.
If you’re on an AMD CPU, you will have something called &lt;code&gt;perfctr_core&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;So, wait, hold on, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.18&#x2F;C&#x2F;ident&#x2F;X86_FEATURE_ARCH_PERFMON&quot;&gt;where&lt;&#x2F;a&gt; is that &lt;code&gt;X86_FEATURE_ARCH_PERFMON&lt;&#x2F;code&gt; capability even
enabled during boot? So, even at boot, the CPU is indicating it can’t support
(v)PMU? Surely not. Surely that’s a mistake. Right?&lt;&#x2F;p&gt;
&lt;p&gt;There’s three places that use the &lt;code&gt;X86_FEATURE_ARCH_PERFMON&lt;&#x2F;code&gt; and that, at first
glance, look relevant to this current situation:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;arch&#x2F;x86&#x2F;events&#x2F;intel&#x2F;core.c&lt;&#x2F;code&gt;, where it’s checked to potentially run a
&lt;code&gt;*_pmu_init&lt;&#x2F;code&gt; function.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;arch&#x2F;x86&#x2F;kernel&#x2F;cpu&#x2F;intel.c&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;arch&#x2F;x86&#x2F;kvm&#x2F;cpuid.c&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Now, if you do not know what &lt;code&gt;cpuid&lt;&#x2F;code&gt; is, don’t worry. We’ll come back to it. All
you need to know, and what i knew at the time, is that it’s a CPU instruction
used to probe features in, and identify CPUs. Let’s investigate the other file
first, okay?&lt;&#x2F;p&gt;
&lt;p&gt;So, what’s going on in &lt;code&gt;intel.c&lt;&#x2F;code&gt;? Well,&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;static void&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; init_intel&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; cpuinfo_x86 &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    early_init_intel&lt;&#x2F;span&gt;&lt;span&gt;(c);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    intel_workarounds&lt;&#x2F;span&gt;&lt;span&gt;(c);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    init_intel_cacheinfo&lt;&#x2F;span&gt;&lt;span&gt;(c);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; (c-&amp;gt;cpuid_level&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        unsigned&lt;&#x2F;span&gt;&lt;span&gt; eax &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; cpuid_eax&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        &#x2F;* Check for version and the number of counters *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span&gt; ((eax &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp; 0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;ff&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt; (((eax&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp; 0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;ff&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            set_cpu_cap&lt;&#x2F;span&gt;&lt;span&gt;(c, X86_FEATURE_ARCH_PERFMON);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Okay. Deep breaths. We’re gonna have to do it. We’re gonna have to-&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Part_3:_We_Have_To_Talk_About_CPUID&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Part_3:_We_Have_To_Talk_About_CPUID&quot; aria-label=&quot;Anchor link for: Part_3:_We_Have_To_Talk_About_CPUID&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Part 3: We Have To Talk About CPUID&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;em&gt;*inhales*&lt;&#x2F;em&gt; &lt;small&gt;(i’ve always wanted to do this)&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The Intel(R) 64 and IA-32 Architecture &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.intel.com&#x2F;content&#x2F;www&#x2F;us&#x2F;en&#x2F;developer&#x2F;articles&#x2F;technical&#x2F;intel-sdm.html&quot;&gt;Software Developer
Manual&lt;&#x2F;a&gt;,
Volume 1, Chapter 21, explains the processor identification and feature
determination instruction, called &lt;code&gt;cpuid&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;CPUID is complex to explain, but, essentially, you interact with it by setting
CPU register &lt;code&gt;eax&lt;&#x2F;code&gt; to a value, and then you observe the output values in &lt;code&gt;eax&lt;&#x2F;code&gt;,
&lt;code&gt;ebx&lt;&#x2F;code&gt;, &lt;code&gt;ecx&lt;&#x2F;code&gt; and potentially &lt;code&gt;edx&lt;&#x2F;code&gt;. For the purpose of probing PMU features, we
set &lt;code&gt;eax=10&lt;&#x2F;code&gt;, as shown above with &lt;code&gt;cpuid_eax(10)&lt;&#x2F;code&gt;. That function is not named
&lt;code&gt;cpuid_eax&lt;&#x2F;code&gt; because it sets &lt;code&gt;eax&lt;&#x2F;code&gt; to 10 by the way, but because it returns only
the value of the &lt;code&gt;eax&lt;&#x2F;code&gt; register after running &lt;code&gt;cpuid&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The notation used within the manual to denote “call to CPUID with EAX=X” is
&lt;code&gt;CPUID.XH&lt;&#x2F;code&gt;. You can then write the different values in the output registers as
&lt;code&gt;CPUID.XH:REGISTER.FIELD_NAME&lt;&#x2F;code&gt;, or with a binary range after the register name.
We’ll be using this notation here too, for coherence with the Intel Software
Developer Manual.&lt;&#x2F;p&gt;
&lt;p&gt;You’re still reading a blog post about QEMU and &lt;code&gt;perf&lt;&#x2F;code&gt; support by the way.&lt;&#x2F;p&gt;
&lt;p&gt;Table 21-30 of the manual presents the list of fields for &lt;code&gt;eax&lt;&#x2F;code&gt; and &lt;code&gt;ebx&lt;&#x2F;code&gt; for
&lt;code&gt;CPUID.0AH&lt;&#x2F;code&gt;. Not all fields really matter here, we are interested in
&lt;code&gt;CPUID.0AH:EAX[7:0]&lt;&#x2F;code&gt; (aka &lt;code&gt;VERSION&lt;&#x2F;code&gt;, aka &lt;code&gt;eax &amp;amp; 0xff&lt;&#x2F;code&gt;), and
&lt;code&gt;CPUID.0AH:EAX[15:8]&lt;&#x2F;code&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-little-end-1&quot;&gt;&lt;a href=&quot;#fn-little-end&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; (aka &lt;code&gt;NUM_GP_CTRS&lt;&#x2F;code&gt;, aka &lt;code&gt;((eax &amp;gt;&amp;gt; 8) &amp;amp; 0xff)&lt;&#x2F;code&gt;), the number of general-purpose hardware counters per core. The manual
says “This leaf is valid if &lt;code&gt;CPUID.OAH:EAX[7:0] &amp;gt; 0&lt;&#x2F;code&gt; and &lt;code&gt;MAX_LEAF&lt;&#x2F;code&gt; ≥ &lt;code&gt;09H&lt;&#x2F;code&gt;”.
Those map exactly with the code above.&lt;&#x2F;p&gt;
&lt;p&gt;So, yeah, that code checks if we have a PMU. Great! Cool. Wait. So, if
&lt;code&gt;X86_FEATURE_ARCH_PERMON&lt;&#x2F;code&gt; is not set, it means that &lt;code&gt;CPUID.0AH:EAX.VERSION&lt;&#x2F;code&gt; is
null, or there’s no general-purpose hardware counters, or the maximum CPUID leaf
is 9 or below. I actually know that it’s the first two, because i then
&lt;em&gt;modified&lt;&#x2F;em&gt; the call as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; (c&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;cpuid_level &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    unsigned&lt;&#x2F;span&gt;&lt;span&gt; eax &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; cpuid_eax&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;* Check for version and the number of counters *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; ((eax &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp; 0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;ff&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt; (((eax&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp; 0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;ff&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        set_cpu_cap&lt;&#x2F;span&gt;&lt;span&gt;(c, X86_FEATURE_ARCH_PERFMON);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    else&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        unsigned&lt;&#x2F;span&gt;&lt;span&gt; ebx &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; cpuid_ebx&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        unsigned&lt;&#x2F;span&gt;&lt;span&gt; ecx &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; cpuid_ecx&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        unsigned&lt;&#x2F;span&gt;&lt;span&gt; edx &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; cpuid_edx&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        pr_warn&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;THERE&amp;#39;S NO PMU AAAAH EAX=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;%x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;, EBX=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;%x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ECX=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;%x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; EDX=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;%x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            eax, ebx, ecx, edx);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And what i got as a result was&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;THERE&amp;#39;S NO PMU AAAAH EAX=0, EBX=0, ECX=0, EDX=0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Fuck.&lt;&#x2F;p&gt;
&lt;p&gt;Ok, quick thinking. Who’s making those responses? Who’s the mastermind behind it
all? That’s right: The Hypervisor.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Part_4:_KVM_is_a_Little_Liar&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Part_4:_KVM_is_a_Little_Liar&quot; aria-label=&quot;Anchor link for: Part_4:_KVM_is_a_Little_Liar&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Part 4: KVM is a Little Liar&lt;&#x2F;h2&gt;
&lt;p&gt;We get to bring in KVM now. Remember the third place where
&lt;code&gt;X86_FEATURE_ARCH_PERFMON&lt;&#x2F;code&gt; was mentioned in that list above? The code is as
follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; &#x2F;* Architectural Performance Monitoring *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    union&lt;&#x2F;span&gt;&lt;span&gt; cpuid10_eax eax;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    union&lt;&#x2F;span&gt;&lt;span&gt; cpuid10_edx edx;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;enable_pmu &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;|| !&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;static_cpu_has&lt;&#x2F;span&gt;&lt;span&gt;(X86_FEATURE_ARCH_PERFMON)) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        entry-&amp;gt;eax&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; entry-&amp;gt;ebx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; entry-&amp;gt;ecx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; entry-&amp;gt;edx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        break&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    eax.split.version_id&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; kvm_pmu_cap.version;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    eax.split.num_counters&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; kvm_pmu_cap.num_counters_gp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    eax.split.bit_width&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; kvm_pmu_cap.bit_width_gp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    eax.split.mask_length&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; kvm_pmu_cap.events_mask_len;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    edx.split.num_counters_fixed&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; kvm_pmu_cap.num_counters_fixed;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    edx.split.bit_width_fixed&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; kvm_pmu_cap.bit_width_fixed;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; (kvm_pmu_cap.version)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        edx.split.anythread_deprecated&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    edx.split.reserved1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    edx.split.reserved2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    entry-&amp;gt;eax&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; eax.full;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    entry-&amp;gt;ebx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; kvm_pmu_cap.events_mask;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    entry-&amp;gt;ecx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    entry-&amp;gt;edx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; edx.full;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    break&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So this is a software implementation of &lt;code&gt;CPUID.0AH&lt;&#x2F;code&gt;! Neat. This is in a function
called &lt;code&gt;__do_cpuid_func&lt;&#x2F;code&gt; in &lt;code&gt;kvm&#x2F;cpuid.c&lt;&#x2F;code&gt;. If you follow the chain of calls all
the way back to
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.18&#x2F;source&#x2F;virt&#x2F;kvm&#x2F;kvm_main.c#L5522&quot;&gt;&lt;code&gt;&#x2F;virt&#x2F;kvm&#x2F;kvm_main.c&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
(&lt;code&gt;__do_cpuid_func&lt;&#x2F;code&gt; ← &lt;code&gt;do_cpuid_func&lt;&#x2F;code&gt; ← &lt;code&gt;get_cpuid_func&lt;&#x2F;code&gt; ←
&lt;code&gt;kvm_dev_ioctl_get_cpuid&lt;&#x2F;code&gt; ← &lt;code&gt;kvm_arch_dev_ioctl&lt;&#x2F;code&gt; ← &lt;code&gt;kvm_dev_ioctl&lt;&#x2F;code&gt;),
you will find the definition of the ioctl handler on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.18&#x2F;source&#x2F;virt&#x2F;kvm&#x2F;kvm_main.c#L5563&quot;&gt;the device that becomes
&lt;code&gt;&#x2F;dev&#x2F;kvm&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.
I hope you already know what an &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Ioctl&quot;&gt;ioctl&lt;&#x2F;a&gt; is.
You wouldn’t be so deep into this post otherwise, probably.&lt;&#x2F;p&gt;
&lt;p&gt;That tracks with my knowledge of how virtualization works in KVM: some
operations are really performed by catching an instruction&#x2F;interrupt&#x2F;whatever
from the VM context, getting out of the VM context, and poking the hypervisor to
query the result that should be given. Here, we’re just doing it with
&lt;code&gt;CPUID.0AH&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;And so, that implementation of &lt;code&gt;CPUID.0AH&lt;&#x2F;code&gt;, how does it synthesize the answer?
Well, as you can see, it checks for &lt;code&gt;enable_pmu&lt;&#x2F;code&gt; and &lt;code&gt;X86_FEATURE_ARCH_PERFMON&lt;&#x2F;code&gt;,
and if either are false&#x2F;disabled, it just sets everything to 0 and returns;
otherwise, it shoves the information we want inside &lt;code&gt;eax&lt;&#x2F;code&gt;, &lt;code&gt;ebx&lt;&#x2F;code&gt; and &lt;code&gt;edx&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;i know that all of my registers were &lt;code&gt;0&lt;&#x2F;code&gt; when i printed them earlier, and
&lt;code&gt;kvm_pmu_cap.version&lt;&#x2F;code&gt; &lt;em&gt;must&lt;&#x2F;em&gt; be above 0, because otherwise the host would have
no PMU, right? But my host has a PMU? i checked at boot:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[    0.116715] Performance Events: XSAVE Architectural LBR, PEBS fmt4+-baseline,  AnyThread deprecated, Alderlake Hybrid events, 32-deep LBR, full-width counters, Intel PMU driver.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[    0.116715] core: cpu_core PMU driver:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[    0.116715] ... version:                   5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[    0.116715] ... bit width:                 48&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[    0.116715] ... generic counters:          8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[    0.116715] ... generic bitmap:            00000000000000ff&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[    0.116715] ... fixed-purpose counters:    4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[    0.116715] ... fixed-purpose bitmap:      000000000000000f&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[    0.116715] ... value mask:                0000ffffffffffff&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[    0.116715] ... max period:                00007fffffffffff&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[    0.116715] ... global_ctrl mask:          0001000f000000ff&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Yeah, version is &lt;code&gt;5&lt;&#x2F;code&gt;! So something’s off. Either &lt;code&gt;enable_pmu&lt;&#x2F;code&gt; is false, or
&lt;code&gt;static_cpu_has&lt;&#x2F;code&gt; fails to find &lt;code&gt;X86_FEATURE_ARCH_PERFMON&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;enable_pmu&lt;&#x2F;code&gt; is defined at
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.18&#x2F;source&#x2F;arch&#x2F;x86&#x2F;kvm&#x2F;x86.c#L185&quot;&gt;&lt;code&gt;arch&#x2F;x86&#x2F;kvm&#x2F;x86.c#L185&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
in v6.18. It is a parameter for the &lt;code&gt;kvm&lt;&#x2F;code&gt; kernel module that defaults to &lt;code&gt;true&lt;&#x2F;code&gt;.
i couldn’t check the actual value, but, considering i had never touched the
default settings on &lt;code&gt;kvm&lt;&#x2F;code&gt;, i assumed it was true? It couldn’t be otherwise. But,
&lt;code&gt;X86_FEATURE_ARCH_PERFMON&lt;&#x2F;code&gt; is also enabled, right? But then that’s impossible. i
mean, the if block should not trigger otherwise, so, like, what’s going on?&lt;&#x2F;p&gt;
&lt;p&gt;What’s going on??&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Part_5:_The_Meltdown&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Part_5:_The_Meltdown&quot; aria-label=&quot;Anchor link for: Part_5:_The_Meltdown&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Part 5: The Meltdown&lt;&#x2F;h2&gt;
&lt;p&gt;So, to summarize what we know so far:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;My host machine boots.&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;code&gt;init_intel&lt;&#x2F;code&gt; function runs, detects maximum leaf count above 9, and a
&lt;code&gt;CPUID.0AH:EAX.VERSION&lt;&#x2F;code&gt; with more than 1 general-purpose counter per core,
so it enables the &lt;code&gt;X86_FEATURE_ARCH_PERFMON&lt;&#x2F;code&gt; capability on the boot CPU.&lt;&#x2F;li&gt;
&lt;li&gt;Later, &lt;code&gt;intel_pmu_init&lt;&#x2F;code&gt; on the host does not trip on the check for that
capability, and the PMU is properly initialized.&lt;&#x2F;li&gt;
&lt;li&gt;The virtual machine boots.&lt;&#x2F;li&gt;
&lt;li&gt;In &lt;code&gt;init_intel&lt;&#x2F;code&gt;, it calls &lt;code&gt;cpuid_eax(10)&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;On the host, an ioctl is fired to &lt;code&gt;&#x2F;dev&#x2F;kvm&lt;&#x2F;code&gt; to synthesize the results of
&lt;code&gt;CPUID.0AH&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;On the host, &lt;code&gt;kvm&lt;&#x2F;code&gt;’s &lt;code&gt;__do_cpuid_func&lt;&#x2F;code&gt; trips on the if to check whether the
PMU is virtualized, and, after setting all registers to 0, returns.&lt;&#x2F;li&gt;
&lt;li&gt;The guest machine receives the answer to &lt;code&gt;cpuid_eax(10)&lt;&#x2F;code&gt;, and does not enable
&lt;code&gt;X86_FEATURE_ARCH_PERFMON&lt;&#x2F;code&gt; on the boot CPU&lt;&#x2F;li&gt;
&lt;li&gt;The guest machine runs &lt;code&gt;intel_pmu_init&lt;&#x2F;code&gt;, which trips on the if block to check
for the &lt;code&gt;arch_perfmon&lt;&#x2F;code&gt; capability.&lt;&#x2F;li&gt;
&lt;li&gt;The family of the CPU being &lt;code&gt;p6&lt;&#x2F;code&gt;, the guest kernel tries to run &lt;code&gt;p6_pmu_init&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;On Linux 6.12, the error “Unsupported CPU” happens directly inside
&lt;code&gt;p6_pmu_init&lt;&#x2F;code&gt;, which returns &lt;code&gt;-ENODEV&lt;&#x2F;code&gt;, which will fail upwards to callers
and fail the PMU initialization as a whole, leaving no access to hardware
counters for &lt;code&gt;perf&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;On Linux 6.18, the error “Unsupported CPU” happens after we check for the
model of the CPU, and realize it’s younger than&#x2F;equal to a Yonah core, so
the &lt;code&gt;p6_pmu_init&lt;&#x2F;code&gt; call is useless, and we fail right now, leaving no
hardware counter available to &lt;code&gt;perf&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;At this point, i tried to fake the calls to &lt;code&gt;cpuid_eax&lt;&#x2F;code&gt; by hard-coding values i
expected, and it did not work. i tried intense googling of more and more obscure
keywords, and it did not work. i tried forcing the &lt;code&gt;enable_pmu&lt;&#x2F;code&gt; parameter on
&lt;code&gt;kvm&lt;&#x2F;code&gt; and reloading &lt;code&gt;kvm_intel&lt;&#x2F;code&gt; too while we’re at it. it didn’t work.&lt;&#x2F;p&gt;
&lt;p&gt;During my googling, i had found a couple of KVM patches from folks trying to
introduce changes to the way KVM handles Hybrid architectures, sometimes
outright disabling it. Remember how my computer has a 13th gen Intel CPU? Most
consumer-grade Intel CPUs starting with 12th gen are heterogeneous&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-cpu-table-1&quot;&gt;&lt;a href=&quot;#fn-cpu-table&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, that is to
say that even though the CPU appears as one coherent unit, the actual cores
inside behave differently: some are optimized for fast tasks but consume more
energy, and others are optimized for tasks that don’t need to be fast, but can
comfortably run slower or sparsely if that means reducing the power draw.&lt;&#x2F;p&gt;
&lt;p&gt;One patch i found discussed issues with KVM and heterogeneous architectures:
unless you properly pin the virtualizing processes on the host, the guest could
receive incoherent messages about hardware counters on its CPUs. Until KVM had a
better way of reasoning between heterogeneous vCPUs and real heterogeneous CPUs
&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-assumptions-1&quot;&gt;&lt;a href=&quot;#fn-assumptions&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, they argued, virtualized PMU should be disabled.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lore.kernel.org&#x2F;all&#x2F;20230120004051.2043777-1-seanjc@google.com&#x2F;&quot;&gt;That patch&lt;&#x2F;a&gt; seemed to make a point, but, checking for its name in the &lt;code&gt;git log&lt;&#x2F;code&gt; of
my version of the kernel, there’s no trace of it.&lt;&#x2F;p&gt;
&lt;p&gt;Out of desperation, i end up trying to grep the individual words, &lt;code&gt;KVM&lt;&#x2F;code&gt;, &lt;code&gt;PMU&lt;&#x2F;code&gt;,
and i skim the output, until i find:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4d7404e5ee00 KVM: x86&#x2F;pmu: Disable vPMU support on hybrid CPUs (host PMUs)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;OH COME ON-&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Part_6:_This_is_Where_i_Complain._A_Lot.&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Part_6:_This_is_Where_i_Complain._A_Lot.&quot; aria-label=&quot;Anchor link for: Part_6:_This_is_Where_i_Complain._A_Lot.&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Part 6: This is Where i Complain. A Lot.&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s inspect commit &lt;code&gt;4d7404e5ee00&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;commit 4d7404e5ee0066e9a9e8268675de8a273b568b08&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Author: Sean Christopherson &amp;lt;seanjc@google.com&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Date:   Wed Feb 8 20:42:29 2023 +0000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    KVM: x86&#x2F;pmu: Disable vPMU support on hybrid CPUs (host PMUs)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Disable KVM support for virtualizing PMUs on hosts with hybrid PMUs until&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    KVM gains a sane way to enumeration the hybrid vPMU to userspace and&#x2F;or&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    gains a mechanism to let userspace opt-in to the dangers of exposing a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    hybrid vPMU to KVM guests.  Virtualizing a hybrid PMU, or at least part of&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    a hybrid PMU, is possible, but it requires careful, deliberate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    configuration from userspace.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    E.g. to expose full functionality, vCPUs need to be pinned to pCPUs to&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prevent migrating a vCPU between a big core and a little core, userspace&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    must enumerate a reasonable topology to the guest, and guest CPUID must be&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    curated per vCPU to enumerate accurate vPMU capabilities.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    The last point is especially problematic, as KVM doesn&amp;#39;t control which&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pCPU it runs on when enumerating KVM&amp;#39;s vPMU capabilities to userspace,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    i.e. userspace can&amp;#39;t rely on KVM_GET_SUPPORTED_CPUID in it&amp;#39;s current form.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Alternatively, userspace could enable vPMU support by enumerating the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    set of features that are common and coherent across all cores, e.g. by&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    filtering PMU events and restricting guest capabilities.  But again, that&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    requires userspace to take action far beyond reflecting KVM&amp;#39;s supported&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    feature set into the guest.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    For now, simply disable vPMU support on hybrid CPUs to avoid inducing&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    seemingly random #GPs in guests, and punt support for hybrid CPUs to a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    future enabling effort.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And so on and so on. I’m sparing you the Signed-off-by’s and the Cc’s and
everything.&lt;&#x2F;p&gt;
&lt;p&gt;The code of the commit is:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;diff&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;diff --git a&#x2F;arch&#x2F;x86&#x2F;kvm&#x2F;pmu.h b&#x2F;arch&#x2F;x86&#x2F;kvm&#x2F;pmu.h&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;index cdb91009701d..ee67ba625094 100644&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FDAEB7;background-color: #86181D;&quot;&gt;--- a&#x2F;arch&#x2F;x86&#x2F;kvm&#x2F;pmu.h&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+++ b&#x2F;arch&#x2F;x86&#x2F;kvm&#x2F;pmu.h&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;font-weight: bold;&quot;&gt;@@ -165,15 +165,27 @@&lt;&#x2F;span&gt;&lt;span&gt; static inline void kvm_init_pmu_capability(void)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        bool is_intel = boot_cpu_data.x86_vendor == X86_VENDOR_INTEL;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FDAEB7;background-color: #86181D;&quot;&gt;-       perf_get_x86_pmu_capability(&amp;amp;kvm_pmu_cap);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FDAEB7;background-color: #86181D;&quot;&gt;-&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FDAEB7;background-color: #86181D;&quot;&gt;-        &#x2F;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FDAEB7;background-color: #86181D;&quot;&gt;-         * For Intel, only support guest architectural pmu&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FDAEB7;background-color: #86181D;&quot;&gt;-         * on a host with architectural pmu.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FDAEB7;background-color: #86181D;&quot;&gt;-         *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FDAEB7;background-color: #86181D;&quot;&gt;-       if ((is_intel &amp;amp;&amp;amp; !kvm_pmu_cap.version) || !kvm_pmu_cap.num_counters_gp)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+       &#x2F;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+        * Hybrid PMUs don&amp;#39;t play nice with virtualization without careful&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+        * configuration by userspace, and KVM&amp;#39;s APIs for reporting supported&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+        * vPMU features do not account for hybrid PMUs.  Disable vPMU support&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+        * for hybrid PMUs until KVM gains a way to let userspace opt-in.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+        *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+       if (cpu_feature_enabled(X86_FEATURE_HYBRID_CPU))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                enable_pmu = false;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+       if (enable_pmu) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+               perf_get_x86_pmu_capability(&amp;amp;kvm_pmu_cap);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+               &#x2F;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+                * For Intel, only support guest architectural pmu&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+                * on a host with architectural pmu.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+                *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+               if ((is_intel &amp;amp;&amp;amp; !kvm_pmu_cap.version) ||&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+                   !kvm_pmu_cap.num_counters_gp)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+                       enable_pmu = false;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+       }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if (!enable_pmu) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                memset(&amp;amp;kvm_pmu_cap, 0, sizeof(kvm_pmu_cap));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                return;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It replaced a check for &lt;code&gt;kvm_pmu_cap.version&lt;&#x2F;code&gt; and &lt;code&gt;num_counters_gp&lt;&#x2F;code&gt; (akin to
what you do with &lt;code&gt;CPUID.0AH&lt;&#x2F;code&gt;) by a cute little if block that checks
&lt;code&gt;X86_FEATURE_HYBRID_CPU&lt;&#x2F;code&gt;, and disables vPMU behind your back if that’s enabled.&lt;&#x2F;p&gt;
&lt;p class=&quot;glitch-text&quot;&gt;&lt;b&gt;Without warning.&lt;&#x2F;b&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In 6.18, there is still no warning there. They only added a &lt;code&gt;memset&lt;&#x2F;code&gt; to zero-out
the &lt;code&gt;kvm_host_pmu&lt;&#x2F;code&gt; structure.&lt;&#x2F;p&gt;
&lt;p&gt;In short, my options are few:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;If i feel like tweaking the host’s kernel, i could comment the line that
disables &lt;code&gt;enable_pmu&lt;&#x2F;code&gt;, and try to work with that (for multiple reasons, it’s
impractical as hell).&lt;&#x2F;li&gt;
&lt;li&gt;Move my experiments to another machine.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;Hidden_Assumptions,_Miscommunication&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Hidden_Assumptions,_Miscommunication&quot; aria-label=&quot;Anchor link for: Hidden_Assumptions,_Miscommunication&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Hidden Assumptions, Miscommunication&lt;&#x2F;h2&gt;
&lt;p&gt;So, let’s recap together what went wrong:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;When &lt;code&gt;perf&lt;&#x2F;code&gt; showed unsupported hardware counters, i searched documentation on
how to enable vPMU, which had no visible date nor indications of
assumptions regarding architecture (in all fairness, a retroactive decision
like that to disable vPMU for all heterogeneous x86 CPUs is not something
people track to then go update blog posts).&lt;&#x2F;li&gt;
&lt;li&gt;The error message in &lt;code&gt;dmesg&lt;&#x2F;code&gt; was originally in a function with a confusing
semantic, that was fixed some time between 6.14 and 6.15 when it moved from
&lt;code&gt;p6_pmu_init&lt;&#x2F;code&gt; to &lt;code&gt;intel_pmu_init&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;The error message talks about an unsupported CPU. It assumes the CPU not
having a PMU exposed via &lt;code&gt;CPUID.0AH&lt;&#x2F;code&gt; is a problem with the model, so it
exposes information related to your CPU model, even when that CPU model
should, by all other indicators, have a PMU.&lt;&#x2F;li&gt;
&lt;li&gt;When i found patch sets on the Linux Kernel Mailing List that discussed vPMU
in KVM, i had no way to track whether they had been merged or not. In fact,
i ended up finding an earlier draft of the commit that bit my ass, but
because it had slightly different commit name formatting, i gave up and
assumed it had not been merged.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;There was no error message about vPMU being forcefully disabled in KVM&lt;&#x2F;strong&gt;.
This decision has several assumptions: the user does not need to know KVM is
running, or they do not know what a hybrid x86 architecture is, or they will
not know &lt;em&gt;why&lt;&#x2F;em&gt; it is disabled, and they will complain because they can’t fix
it. It still baffles me that nobody thought to at least print &lt;em&gt;something&lt;&#x2F;em&gt;,&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Look, i am used to this. i am used to falling through the cracks of people’s
assumptions: i daily-drive Arch Linux, i run shit on QEMU via the command line
only, i build my own kernel modules sometimes, i need old software, i jam
programs together that were never meant to work together. There’s glue though,
there’s things we, as people who touch computers have agreed on in order for
communication to work properly across implementations. CPUID is one such
example, and so are ioctls, kernel module parameters, network protocols, perf
sample representations, or even &lt;em&gt;logging messages&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Logging is the most person-oriented way of conveying that something went wrong,
or any complex information that cannot be shoved in a bitfield for easy access:
when i read the message about “Unsupported CPU”, that was a programmer, 14 years
ago, telling me “Hey, if you hit this line of code, it means you plugged a CPU
into your motherboard that does not have a PMU yet!”. For a second, someone’s
thought process was conveyed to me, alongside their assumptions about the
meaning of a Intel CPU reporting no &lt;code&gt;arch_perfmon&lt;&#x2F;code&gt; capability.&lt;&#x2F;p&gt;
&lt;p&gt;Look, i’m not blaming the Linux devs. Entirely. There may be reasonable
arguments for why they did not add a log line in that if block, or why nobody
thought about adding that at any point in reviewing the sets. Maybe they had
assumptions about the users, about the systems, that they did not communicate.&lt;&#x2F;p&gt;
&lt;p&gt;i’m more mad about how we keep miscommunicating at each other, especially about
assumptions we make about hardware, software, their interactions, and how i keep
losing my time and my mind debugging the friction between all of them.&lt;&#x2F;p&gt;
&lt;p&gt;It’s tiring, frankly.&lt;&#x2F;p&gt;
&lt;p&gt;…&lt;&#x2F;p&gt;
&lt;p&gt;Oh and fuck Intel, really while we’re at it. That’s all. Bye!&lt;&#x2F;p&gt;
&lt;!-- vim: set spell spelllang=en cc=80 tw=80: --&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-little-end&quot;&gt;
&lt;p&gt;Notice how the Intel Software Developer manual does bit ranges
backwards? Ah, little endian architectures… &lt;a href=&quot;#fr-little-end-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-cpu-table&quot;&gt;
&lt;p&gt;To be more precise, mainstream desktop 12th gen Alderlake CPUs are
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Alder_Lake#Dies&quot;&gt;still homogeneous&lt;&#x2F;a&gt;. Thirteenth
gen, aka &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Raptor_Lake&quot;&gt;Raptor Lake&lt;&#x2F;a&gt;, are
heterogeneous except for i3s, and similarly for the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Raptor_Lake#Raptor_Lake-S_Refresh&quot;&gt;14th gen&lt;&#x2F;a&gt;. &lt;a href=&quot;#fr-cpu-table-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-assumptions&quot;&gt;
&lt;p&gt;So, i’m not a KVM fox. i’m not even that much of an architecture
fox, i just know people, and i hate hardware with a passion so intense that
occasionally i end up learning way too much about it. My assumptions about
the more precise problems with KVM and heterogeneous architectures, from
what i understood, is that the available performance counters exposed on the
host are those of the performance CPUs, which are typically more advanced.
Those are also the sets exposed to the guest. However, if the guest is
scheduled on an efficiency CPU, and tries to probe a counter that is
only available on a performance CPU, it will fail, or there will be
undefined behaviour that has never been accounted for anywhere so far in the
kernel or &lt;code&gt;perf&lt;&#x2F;code&gt;. Another assumption is that exposing which CPU you’re
currently scheduled on to the guest is… a gamble. Knowing your position in
a topology, especially if you’re a malicious actor, especially if you’re
scheduled with other users of a system, opens up a lot of possibilities to
probe your cache neighbours, or even mess with them. &lt;a href=&quot;#fr-assumptions-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Guarding My Git Forge Against AI Scrapers</title>
        <published>2025-12-02T00:00:00+00:00</published>
        <updated>2026-03-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/guarding-git-forge-ai-scrapers/"/>
        <id>https://vulpinecitrus.info/blog/guarding-git-forge-ai-scrapers/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/guarding-git-forge-ai-scrapers/">&lt;p&gt;In August 2024, one of my roommates and partners messaged the apartment group
chat, saying she noticed the internet was slow again at our place, and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;&quot;&gt;my
forgejo&lt;&#x2F;a&gt; was unable to render &lt;em&gt;any&lt;&#x2F;em&gt; page in
under 15 seconds.&lt;&#x2F;p&gt;
&lt;p&gt;i investigated, thinking it would be a trivial little problem to solve. Soon
enough, however, i would uncover hundreds of thousands of queries a day from
thousands of individual IPs, fetching seemingly-random pages in my forge
every single day, all the time.&lt;&#x2F;p&gt;
&lt;p&gt;This post summarizes the practical issues that arose as a result of the onslaught
of scrapers eager to download millions of commits off of my forge, and the
measures i put in place to limit the damage.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Why_the_forge?&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Why_the_forge?&quot; aria-label=&quot;Anchor link for: Why_the_forge?&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Why the forge?&lt;&#x2F;h1&gt;
&lt;p&gt;In the year 2025, on the web, everything is worth being scraped. Everything
that came out of the mind of a human is susceptible to be snatched under the
vastest labor theft scheme in the history of mankind. This very article, the
second it gets published in any indexable page, will be added to countless
datasets meant to train foundational large-language models. My words, your
words, have contributed infinitesimal shifts of neural-network weights
underpinning the largest, most grotesque accumulation of wealth seen over the
lifetime of my parents, grandparents, and their grandparents themselves.&lt;&#x2F;p&gt;
&lt;p&gt;Oh, and forges have a lot of commits. See, if you have a public repository that
is publicly exposed, every file in every folder for every commit will be connected.
Add other options, such as a &lt;code&gt;git blame&lt;&#x2F;code&gt; on a file, and multiply it by the
number of files and commits. Add the raw download link, also multiplied by the
number of commits.&lt;&#x2F;p&gt;
&lt;p&gt;Say, hypothetically, you have a linux repository available, and only with
all the commits in the &lt;code&gt;master&lt;&#x2F;code&gt; branch up to the &lt;code&gt;v6.17&lt;&#x2F;code&gt; tag from 2025-09-18.
That’s 1,383,738 commits in the range &lt;code&gt;1da177e4c3f4..e5f0a698b34e&lt;&#x2F;code&gt;. How many
files is that? Well:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;count=0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;while read -r rev; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    point=$(git ls-tree -tr $rev | wc -l);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    count=$(( $count + $point ));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    printf &amp;quot;[%s] %s: %d (tot: %d)\n&amp;quot; $(git log -1 --pretty=tformat:%cs $rev) $rev $point $count;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;done &amp;lt; &amp;lt;(git rev-list &amp;quot;1da177e4c3f4..e5f0a698b34e&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;printf &amp;quot;Total: $count\n&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;i ran this on the 100 commits before &lt;code&gt;v6.17&lt;&#x2F;code&gt;. If you have &lt;code&gt;git ls-tree -tr $rev&lt;&#x2F;code&gt;, you get both files and directories counted. If you replace it with &lt;code&gt;git ls-tree -r $rev&lt;&#x2F;code&gt; only shows files. i got 72024729 files, and 76798658 files and
directories. Running on the whole history of Linux’s &lt;code&gt;master&lt;&#x2F;code&gt; branch yields
78,483,866,182 files, and 83,627,462,277 files and directories.&lt;&#x2F;p&gt;
&lt;p&gt;Now, for a ballpark estimate of the number of pages that can be scraped if you
have a copy of Linux, apply the formula:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(Ncommits * Nfiles) * 2 + (Ncommits * Nfilesandfolders) * 2 + Ncommits * 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That is, applied to my hypothetical Linux repository:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;78483866182 * 2 + 83627462277 * 2 + 1383738 * 3 = 324,226,808,132 pages&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;*3&lt;&#x2F;code&gt; accounts for the fact that every file of every commit can be scraped
raw, and &lt;code&gt;git-blame&lt;&#x2F;code&gt;’d. The second part of the
formula considers every single file or folder page. The third part accounts for
the fact that every file of every commit can be diffed with its version of
every commit (in theory). The final component considers every commit summary
page.&lt;&#x2F;p&gt;
&lt;p&gt;That gives, for me, 324 billion 226 million 808 thousand and 132 pages that can
be scraped. From a single repository. Assume that every scraper agent that
enters one of these repositories will also take note of every other link on the
page, and report it so that other agents can scrapes them. These scrapers
effectively act like early 2000s web spiders that crawled the internet to index
it, except they do not care about &lt;code&gt;robots.txt&lt;&#x2F;code&gt;, and they will absolutely keep
scraping new links again and again with no strategy to minimize the cost on
you, as a host.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;The_Cost_of_Scraping&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#The_Cost_of_Scraping&quot; aria-label=&quot;Anchor link for: The_Cost_of_Scraping&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
The Cost of Scraping&lt;&#x2F;h1&gt;
&lt;p&gt;As i am writing the original draft of this section, the longer-term measures i
put in place have been removed, so i could gather up-to-date numbers to display
how bad the situation is.&lt;&#x2F;p&gt;
&lt;p&gt;i pay for the electricity that powers my git Forge. Okay, actually, one of my
roommate does, but we put it on the calc sheet where we keep track of who pays
what &lt;small&gt;(when we remember)&lt;&#x2F;small&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;At the time i began fighting scrapers, my git forge ran from an old desktop
computer plugged in my living room. Now, it is in our home’s rackable server
in a virtual machine. i never got to measure differences in power consumption
when we got scraped or not scraped on the desktop machine, but i did on the
rackable server. If memory serves me right, stopping the wave of scrapers reduced
the power draw of the server from ~170W to ~150W.&lt;&#x2F;p&gt;
&lt;p&gt;Right now, with all the hard drives in that server spinning, and every protection
off, we are drawing 200W from the power grid on that server. Constantly. By the
end of this experiment, me and my roommates will have computed that the difference
in power usage caused by scraping costs us ~60 euros a year.&lt;&#x2F;p&gt;
&lt;p&gt;Another tied cost is that the VM that runs the forge is figuratively &lt;em&gt;suffocating&lt;&#x2F;em&gt;
from the amount of queries. Not all queries are born equal as well: requests to
see the &lt;code&gt;blame&lt;&#x2F;code&gt; of a file or a &lt;code&gt;diff&lt;&#x2F;code&gt; between commits incurs a worse cost than
just rendering the front page of a repository. The last huge wave of scraping
left my VM at &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eldritch.cafe&#x2F;@SharpLimefox&#x2F;115134284600855853&quot;&gt;99+% usage of 4 CPU cores and 2.5GiB of RAM&lt;&#x2F;a&gt;,
whereas the usual levels i observe are closer to 4% usage of CPUs, and an oscillation
between 1.5GiB and 2GiB of RAM.&lt;&#x2F;p&gt;
&lt;p&gt;As i’m writing this, the VM running forgejo eats 100% of 8 CPU cores.&lt;&#x2F;p&gt;
&lt;p&gt;Additionally, the networking cost is palpable. Various monitoring tools let me see
the real-time traffic statistics in our apartment. Before i put the first
measures in place to thwart scraping, we could visibly see the traffic coming out
of the desktop computer running my forge and out to the internet. My roommates’
complaints that it slowed down the whole internet here were in fact founded: when
we had multiple people watching live streams or doing pretty big downloads, they
were throttled by the traffic out of the forge.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-qos-1&quot;&gt;&lt;a href=&quot;#fn-qos&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The egress data rate of my forge’s VM is at least 4MBps of data (32Mbps). Constantly.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, the human cost: i have spent &lt;strong&gt;entire days&lt;&#x2F;strong&gt; behind my terminals
trying to figure out 1) what the fuck was going on and 2) what the fuck to do
about it. i have had conversations with other people who self-host their
infrastructure, desperately trying to figure out workable solutions that would
not needlessly impact our users. And the funniest detail is: that rackable
server is in the living room, directly in front of my bedroom door. It usually
purrs like an adorable cat, but, lately, it’s been whirring louder and louder.
&lt;em&gt;i can hear it. when i’m trying to sleep&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Let’s_do_some_statistics.&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Let’s_do_some_statistics.&quot; aria-label=&quot;Anchor link for: Let’s_do_some_statistics.&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Let’s do some statistics.&lt;&#x2F;h1&gt;
&lt;p&gt;i was curious to analyze the nginx logs to understand where the traffic came
from and what shape it took.&lt;&#x2F;p&gt;
&lt;p&gt;As a study case, we can work on &lt;code&gt;&#x2F;var&#x2F;log&#x2F;nginx&#x2F;git.vulpinecitrus.info&#x2F;&lt;&#x2F;code&gt; from
&lt;code&gt;2025-11-14&lt;&#x2F;code&gt; to &lt;code&gt;2025-11-19&lt;&#x2F;code&gt;. Note that on &lt;code&gt;2025-11-15&lt;&#x2F;code&gt; at &lt;code&gt;18:27 UTC&lt;&#x2F;code&gt;, i
stopped the redirection of new agents into the Iocaine crawler maze (see
below). At &lt;code&gt;19:15 UTC&lt;&#x2F;code&gt;, i removed the nginx request limit zone from the
&lt;code&gt;&#x2F;Lymkwi&#x2F;linux&#x2F;&lt;&#x2F;code&gt; path. At &lt;code&gt;19:16 UTC&lt;&#x2F;code&gt; i removed the separation of log files
between IPs flagged as bots, and IPs not flagged as bots.&lt;&#x2F;p&gt;
&lt;p&gt;The three measures i progressively put in place later were: web caching
(2025-11-17), manually sending IPs to a garbage generator with a rate-limit
(Iocaine 2) (2025-11-14, 15 and 18), and then &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;iocaine.madhouse-project.org&quot;&gt;Iocaine
3&lt;&#x2F;a&gt; (2025-11-19).&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Common Logs&lt;&#x2F;th&gt;&lt;th&gt;Successful&lt;&#x2F;th&gt;&lt;th&gt;Delayed (429)&lt;&#x2F;th&gt;&lt;th&gt;Error (5XX)&lt;&#x2F;th&gt;&lt;th&gt;Measures in place&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2025-11-14&lt;&#x2F;td&gt;&lt;td&gt;275323&lt;&#x2F;td&gt;&lt;td&gt;66517&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;Iocaine 2.1 + Rate-limiting&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-15&lt;&#x2F;td&gt;&lt;td&gt;71712&lt;&#x2F;td&gt;&lt;td&gt;54259&lt;&#x2F;td&gt;&lt;td&gt;9802&lt;&#x2F;td&gt;&lt;td&gt;Iocaine 2.1 + Rate-limiting&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-16&lt;&#x2F;td&gt;&lt;td&gt;140713&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;65763&lt;&#x2F;td&gt;&lt;td&gt;None&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-17&lt;&#x2F;td&gt;&lt;td&gt;514309&lt;&#x2F;td&gt;&lt;td&gt;25986&lt;&#x2F;td&gt;&lt;td&gt;3012&lt;&#x2F;td&gt;&lt;td&gt;Caching, eventually rate-limiting&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-cache-failure-1&quot;&gt;&lt;a href=&quot;#fn-cache-failure&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-18&lt;&#x2F;td&gt;&lt;td&gt;335266&lt;&#x2F;td&gt;&lt;td&gt;20280&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;Iocaine 2.1 + Rate-limiting&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-19&lt;&#x2F;td&gt;&lt;td&gt;3183&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;Iocaine 3&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Bot Logs&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;Successful&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;Delayed (429)&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;Error (5XX)&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;Measures in place&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-14 (bots)&lt;&#x2F;td&gt;&lt;td&gt;41388&lt;&#x2F;td&gt;&lt;td&gt;65517&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;Iocaine 2.1 + Rate-limiting&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-15 (bots)&lt;&#x2F;td&gt;&lt;td&gt;34190&lt;&#x2F;td&gt;&lt;td&gt;53403&lt;&#x2F;td&gt;&lt;td&gt;63&lt;&#x2F;td&gt;&lt;td&gt;Iocaine 2.1 + Rate-limiting&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-16 (bots)&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;(no bot-specific logs)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-17 (bots)&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;(no bot-specific logs)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-18 (bots)&lt;&#x2F;td&gt;&lt;td&gt;390013&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;td&gt;Iocaine 2.1 + Rate-limiting&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-19 (bots)&lt;&#x2F;td&gt;&lt;td&gt;731593&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;Iocaine 3&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;div style=&quot;text-align: center;padding-top: .5em; padding-bottom: 1em;&quot;&gt;&lt;b&gt;&lt;u&gt;Table 1: Number of Queries Per Day&lt;&#x2F;u&gt;&lt;&#x2F;b&gt;&lt;&#x2F;div&gt;
&lt;details&gt;
&lt;summary&gt;(Commands used to generate Table 1)&lt;&#x2F;summary&gt;
&lt;p&gt;Assuming your log file is &lt;code&gt;git-access-2025-11-14.log.gz&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;zcat git-access-2025-11-14.log.gz | grep &amp;#39;&amp;quot; 200 &amp;#39; | wc -l&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;zcat git-access-2025-11-14.log.gz | grep &amp;#39;&amp;quot; 429 &amp;#39; | wc -l&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;Without spoiling too much, caching was an utter failure, and the improvement i
measurement by manually rate-limiting a set of IPs (from Huawei Cloud and Alibaba)
on the Linux repository only helped so much. When all protections dropped, my
server became so unresponsive that backend errors (usually timeouts) spiked.
Error also happened with caching, when nginx encountered an issue when buffering
a reply. Overall, caching encouraged more queries overall.&lt;&#x2F;p&gt;
&lt;p&gt;Once Iocaine was deployed, the vast majority of queries were routed away from
the backend, with no errors reported, and no delaying because all of the IPs
i manually rate-limited were caught by Iocaine instead.&lt;&#x2F;p&gt;
&lt;p&gt;Out of all these queries, &lt;code&gt;117.64.70.34&lt;&#x2F;code&gt; is the most common source of requests,
with 226023 total queries originating from the ChinaNet-Backbone ASN (AS4134).
It is followed by &lt;code&gt;136.243.228.193&lt;&#x2F;code&gt; (13849 queries), an IP from Hetzner whose
hostname ironically resolves to
&lt;code&gt;crawling-gateway-136-243-228-193.dataforseo.com&lt;&#x2F;code&gt;. Then, &lt;code&gt;172.17.0.3&lt;&#x2F;code&gt; the
uptime prober of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;status.vulpinecitrus.info&quot;&gt;VC Status&lt;&#x2F;a&gt; with 6908
queries, and &lt;code&gt;74.7.227.127&lt;&#x2F;code&gt;, an IP from Microsoft’s AS 8075 (6117 queries).&lt;&#x2F;p&gt;
&lt;div class=&quot;table_wrapper&quot;&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Day&lt;&#x2F;th&gt;&lt;th&gt;Unique IP Count&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2025-11-14&lt;&#x2F;td&gt;&lt;td&gt;16461&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-15&lt;&#x2F;td&gt;&lt;td&gt;18639&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-16&lt;&#x2F;td&gt;&lt;td&gt;41712&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-17&lt;&#x2F;td&gt;&lt;td&gt;47252&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-18&lt;&#x2F;td&gt;&lt;td&gt;22480&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-19&lt;&#x2F;td&gt;&lt;td&gt;14230&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;&#x2F;div&gt;
&lt;div style=&quot;text-align: center;padding-top: .5em; padding-bottom: 1em;&quot;&gt;&lt;b&gt;&lt;u&gt;Table 2: Grand Total of Unique IPs Querying the Forge&lt;&#x2F;u&gt;&lt;&#x2F;b&gt;&lt;&#x2F;div&gt;
&lt;details&gt;
&lt;summary&gt;(Commands used to generate Table 2)&lt;&#x2F;summary&gt;
&lt;p&gt;Assuming your log files are called &lt;code&gt;*git-access-2025-11-14.log.gz&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;zcat \*git-access-2025-11-14.log.gz | awk &amp;#39;{ print $1 }&amp;#39; | sort | uniq -c | wc -l&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;On the two days where restrictions were lifted or there was only caching, the
amount of unique IPs querying the forge doubled. The more you facilitate the
work of these crawlers, the more they are going to pound you. They will always
try and get more out of your server than you are capable of providing.&lt;&#x2F;p&gt;
&lt;div class=&quot;table_wrapper&quot;&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Day&lt;&#x2F;th&gt;&lt;th&gt;Top 1&lt;&#x2F;th&gt;&lt;th&gt;Top 2&lt;&#x2F;th&gt;&lt;th&gt;Top 3&lt;&#x2F;th&gt;&lt;th&gt;Top 4&lt;&#x2F;th&gt;&lt;th&gt;Top 5&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2025-11-14&lt;&#x2F;td&gt;&lt;td&gt;(226089) - &lt;code&gt;&#x2F;reibooru&#x2F;reibooru&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(40189) - &lt;code&gt;&#x2F;Lymkwi&#x2F;linux&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(1454) - &lt;code&gt;&#x2F;&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(1405) - &lt;code&gt;&#x2F;rail&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(1174) - &lt;code&gt;&#x2F;Soblow&#x2F;indi-hugo&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-15&lt;&#x2F;td&gt;&lt;td&gt;(35163) - &lt;code&gt;&#x2F;Lymkwi&#x2F;linux&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(18952) - &lt;code&gt;&#x2F;vc-archival&#x2F;youtube-dl&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(4197) - &lt;code&gt;&#x2F;vc-archival&#x2F;youtube-dl-original&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(1655) - &lt;code&gt;&#x2F;reibooru&#x2F;reibooru&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(1635) - &lt;code&gt;&#x2F;Lymkwi&#x2F;gr-gsm&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-14 (bots)&lt;&#x2F;td&gt;&lt;td&gt;(40189) - &lt;code&gt;&#x2F;Lymkwi&#x2F;linux&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(270) - &lt;code&gt;&#x2F;oror&#x2F;necro&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(79) - &lt;code&gt;&#x2F;Lymkwi&#x2F;[REDACTED]&lt;&#x2F;code&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-redacted-1&quot;&gt;&lt;a href=&quot;#fn-redacted&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;td&gt;&lt;td&gt;(55) - &lt;code&gt;&#x2F;vc-archival&#x2F;youtube-dl&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(52) - &lt;code&gt;&#x2F;oror&#x2F;asm&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-15 (bots)&lt;&#x2F;td&gt;&lt;td&gt;(32895) - &lt;code&gt;&#x2F;Lymkwi&#x2F;linux&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(260) - &lt;code&gt;&#x2F;oror&#x2F;necro&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(193) - &lt;code&gt;&#x2F;Lymkwi&#x2F;gr-gsm&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(95) - &lt;code&gt;&#x2F;Lymkwi&#x2F;[REDACTED]&lt;&#x2F;code&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-redacted-2&quot;&gt;&lt;a href=&quot;#fn-redacted&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;td&gt;&lt;td&gt;(48) - &lt;code&gt;&#x2F;alopexlemoni&#x2F;GenderDysphoria.fyi&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-16&lt;&#x2F;td&gt;&lt;td&gt;(72687) - &lt;code&gt;&#x2F;vc-archival&#x2F;youtube-dl&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(23028) - &lt;code&gt;&#x2F;Lymkwi&#x2F;linux&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(16779) - &lt;code&gt;&#x2F;vc-archival&#x2F;youtube-dl-original&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(5390) - &lt;code&gt;&#x2F;reibooru&#x2F;reibooru&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(3585) - &lt;code&gt;&#x2F;Lymkwi&#x2F;gr-gsm&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-17&lt;&#x2F;td&gt;&lt;td&gt;(361632) - &lt;code&gt;&#x2F;vc-archival&#x2F;youtube-dl&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(74048) - &lt;code&gt;&#x2F;vc-archival&#x2F;youtube-dl-original&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(18136) - &lt;code&gt;&#x2F;reibooru&#x2F;reibooru&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(13147) - &lt;code&gt;&#x2F;oror&#x2F;necro&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(12921) - &lt;code&gt;&#x2F;alopexlemoni&#x2F;GenderDysphoria.fyi&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-18&lt;&#x2F;td&gt;&lt;td&gt;(227019) - &lt;code&gt;&#x2F;vc-archival&#x2F;youtube-dl&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(46004) - &lt;code&gt;&#x2F;vc-archival&#x2F;youtube-dl-original&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(12644) - &lt;code&gt;&#x2F;alopexlemoni&#x2F;GenderDysphoria.fyi&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(12624) - &lt;code&gt;&#x2F;reibooru&#x2F;reibooru&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(7712) - &lt;code&gt;&#x2F;oror&#x2F;necro&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-18 (bots)&lt;&#x2F;td&gt;&lt;td&gt;(261346) - &lt;code&gt;&#x2F;vc-archival&#x2F;youtube-dl&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(43923) - &lt;code&gt;&#x2F;vc-archival&#x2F;youtube-dl-original&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(20195) - &lt;code&gt;&#x2F;alopexlemoni&#x2F;GenderDysphoria.fyi&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(18808) - &lt;code&gt;&#x2F;reibooru&#x2F;reibooru&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(10134) - &lt;code&gt;&#x2F;oror&#x2F;necro&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-19&lt;&#x2F;td&gt;&lt;td&gt;(1418) - &lt;code&gt;&#x2F;&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(1248) - &lt;code&gt;&#x2F;rail&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(356) - &lt;code&gt;&#x2F;Soblow&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(31) - &lt;code&gt;&#x2F;assets&#x2F;img&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(25) - &lt;code&gt;&#x2F;Soblow&#x2F;IndigoDen&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025-11-19 (bots)&lt;&#x2F;td&gt;&lt;td&gt;(448626) - &lt;code&gt;&#x2F;vc-archival&#x2F;youtube-dl&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(73164) - &lt;code&gt;&#x2F;vc-archival&#x2F;youtube-dl-original&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(39107) - &lt;code&gt;&#x2F;reibooru&#x2F;reibooru&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(37107) - &lt;code&gt;&#x2F;alopexlemoni&#x2F;GenderDysphoria.fyi&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;(25921) - &lt;code&gt;&#x2F;vc-archival&#x2F;YSLua&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;&#x2F;div&gt;
&lt;div id=&quot;tab_3&quot; style=&quot;text-align: center;padding-top: .5em; padding-bottom: 1em;&quot;&gt;&lt;b&gt;&lt;u&gt;Table 3: Top 5 Successful Repo&#x2F;Account&#x2F;Page Hits Per Day&lt;&#x2F;u&gt;&lt;&#x2F;b&gt;&lt;&#x2F;div&gt;
&lt;details&gt;
&lt;summary&gt;(Commands used to generate Table 3)&lt;&#x2F;summary&gt;
&lt;p&gt;Assuming you want data for the log file called &lt;code&gt;git-access-2025-11-14.log.gz&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; zcat git-access-2025-11-14.log.gz | grep &amp;#39;&amp;quot; 200 &amp;#39; | awk &amp;#39;{ print $7 }&amp;#39; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | cut -d&#x2F; -f -3 | sort | uniq -c | sort -n \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | tail -n 5 | tac&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;Big repositories with a lot of commits and a lot of files are a bountiful resource
for the crawlers. Once they enter those, they will take ages to leave, at least because of the
sheer amount of pages that can be generated by following the links of a repository.&lt;&#x2F;p&gt;
&lt;p&gt;Most legitimate traffic seems to be either fetching profiles (a couple of my users
have their profiles listed in their fediverse bios) or the root page of my forge.&lt;&#x2F;p&gt;
&lt;div class=&quot;table_wrapper&quot;&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;&#x2F;th&gt;&lt;th&gt;2025-11-14 (all)&lt;&#x2F;th&gt;&lt;th&gt;2025-11-15 (all)&lt;&#x2F;th&gt;&lt;th&gt;2025-11-16 (all)&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Top 1&lt;&#x2F;td&gt;&lt;td&gt;(8532) - AS136907 (Huawei Clouds)&lt;&#x2F;td&gt;&lt;td&gt;(8537) - AS136907 (Huawei Clouds)&lt;&#x2F;td&gt;&lt;td&gt;(8535) - AS136907 (Huawei Clouds)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Top 2&lt;&#x2F;td&gt;&lt;td&gt;(2142) - AS45899 (VNPT Corp)&lt;&#x2F;td&gt;&lt;td&gt;(2107) - AS45899 (VNPT Corp)&lt;&#x2F;td&gt;&lt;td&gt;(4002) - AS212238 (Datacamp Limited)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Top 3&lt;&#x2F;td&gt;&lt;td&gt;(803) - AS153671 (Liasail Global Hongkong Limited)&lt;&#x2F;td&gt;&lt;td&gt;(895) - AS153671 (Liasail Global Hongkong Limited)&lt;&#x2F;td&gt;&lt;td&gt;(3504) - AS9009 (M247 Europe SRL)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Top 4&lt;&#x2F;td&gt;&lt;td&gt;(555) - AS5065 (Bunny Communications)&lt;&#x2F;td&gt;&lt;td&gt;(765) - AS45102 (Alibaba US Technology Co., Ltd.)&lt;&#x2F;td&gt;&lt;td&gt;(3206) - AS3257 (GTT Communications)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Top 5&lt;&#x2F;td&gt;&lt;td&gt;(390) - AS21859 (Zenlayer Inc)&lt;&#x2F;td&gt;&lt;td&gt;(629) - AS5065 (Bunny Communications)&lt;&#x2F;td&gt;&lt;td&gt;(2874) - AS45899 (VNPT Corp)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;&#x2F;div&gt;
&lt;div id=&quot;tab_4&quot; style=&quot;text-align: center;padding-top: .5em; padding-bottom: 1em;&quot;&gt;&lt;b&gt;&lt;u&gt;Table 4: Top ASN Per Day For The First Three Days, Per Unique IP Count&lt;&#x2F;u&gt;&lt;&#x2F;b&gt;&lt;&#x2F;div&gt;
&lt;details&gt;
&lt;summary&gt;(Commands used to generate Table 4)&lt;&#x2F;summary&gt;
&lt;p&gt;For this, i needed a database of IP-to-ASN data. i got one from
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;ipinfo.io&quot;&gt;IPInfo&lt;&#x2F;a&gt; by registering for a free account and using their
web API. i first scripted a mapping of unique IP addresses to AS number. For
example, for the log file &lt;code&gt;bot-git-access-2025-11-18.log.gz&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;while read ip; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ASN=$(curl -qfL api.ipinfo.io&#x2F;lite&#x2F;$ip?token=&amp;lt;my token&amp;gt; | jq -r .asn);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    printf &amp;quot;$ip $ASN\n&amp;quot; | tee -a 2025-11-18-bot.ips.txt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;done &amp;lt; &amp;lt;(zcat bot-git-access-2025-11-18.log.gz | awk &amp;#39;{ print $1 }&amp;#39; | sort | uniq)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, with this map, i run:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cat 2025-11-18-bot.ips.txt | cut -d&amp;#39; &amp;#39; -f 2 | sort | uniq -c | sort -n | tail -n 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;So my largest hits are from Huawei Clouds (VPS provider), VPNT (a Vietnamese mobile and home ISP),
Liasail Global HK Limited (a VPS&#x2F;“AI-powering service” provider),
Bunny Communications LLC (a broadband ISP for residential users), and Zenlayer (CDN&#x2F;Cloud infrastructure provider).
When i lifted all protections, Datacamp Limited (a VPS provider), GTT Communications (some sort of bullshit-looking ISP&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-gtt-1&quot;&gt;&lt;a href=&quot;#fn-gtt&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; who, i have been informed, is in fact a backbone operator), and M247 Europe SRL (a hosting provider) suddenly appeared. If memory serves me right, Datacamp, GTT and M247 were also
companies i had flagged during my initial investigation in summer 2024, and added to the manually blocked&#x2F;limited IPs alongside
all of Huawei Cloud and Alibaba.&lt;&#x2F;p&gt;
&lt;p&gt;Interestingly, both Liasail and Zenlayer mention that they “Power AI” on their front page. They sure do.
Worryingly, VNPT and Bunny Communications are &lt;em&gt;home&#x2F;mobile ISPs&lt;&#x2F;em&gt;. i cannot ascertain for sure that
their IPs are from domestic users, but it seems worrisome that these are among the top scraping sources once
you remove the most obviously malicious actors.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;The_Protection_Measures&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#The_Protection_Measures&quot; aria-label=&quot;Anchor link for: The_Protection_Measures&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
The Protection Measures&lt;&#x2F;h1&gt;
&lt;p&gt;i have one goal, and one constraint. My goal is that i need to protect the forge
as much as possible, by means of either blocking bots or offloading the cost to
my VPS provider (whose electricity i do not pay for). My only constraint: i was
not going to deploy a proof-of-work-based captcha system such as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;anubis.techaro.lol&#x2F;&quot;&gt;Anubis&lt;&#x2F;a&gt;.
There are two reasons for these constraints:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;i personally find that forcing your visitors to have to expand more computational power to prove they’re not a scraper is
bad praxis. There are devices out there that legitimately want that access, but have
limited computational power or features. And, yeah, there are &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;anubis.techaro.lol&#x2F;docs&#x2F;admin&#x2F;configuration&#x2F;challenges&#x2F;&quot;&gt;multiple types of challenges&lt;&#x2F;a&gt;, some of which &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;anubis.techaro.lol&#x2F;docs&#x2F;admin&#x2F;configuration&#x2F;challenges&#x2F;preact&#x2F;&quot;&gt;take low-power devices into account&lt;&#x2F;a&gt; or even &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;anubis.techaro.lol&#x2F;docs&#x2F;admin&#x2F;configuration&#x2F;challenges&#x2F;metarefresh&#x2F;&quot;&gt;those that cannot run JavaScript&lt;&#x2F;a&gt;, but,&lt;&#x2F;li&gt;
&lt;li&gt;Scrapers can easily bypass Anubis. It’s not a design flaw. Anubis is harm
reduction, not pixie dust.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;i tried layers of solutions:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;caching on the reverse proxy&lt;&#x2F;li&gt;
&lt;li&gt;Iocaine 2 with no classifiers, which generates garbage in reply to any query
you send it&lt;&#x2F;li&gt;
&lt;li&gt;Manually redirecting IPs and rate-limiting them&lt;&#x2F;li&gt;
&lt;li&gt;Deploying Iocaine 3, with its classifiers (Nam-Shub-of-Enki)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;Reverse-Proxy_Caching&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Reverse-Proxy_Caching&quot; aria-label=&quot;Anchor link for: Reverse-Proxy_Caching&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Reverse-Proxy Caching&lt;&#x2F;h2&gt;
&lt;p&gt;i have a confession to make: i never realized that nginx did not cache anything
by default. That realization promptly came with the other realization that
&lt;em&gt;caching things correctly is hard&lt;&#x2F;em&gt;. i may, some day, write about my experience
of protecting a service that posted links to itself on the fediverse, so that
it wouldn’t slow to a crawl for ten minutes after every post.&lt;&#x2F;p&gt;
&lt;p&gt;As for the rest of these, i will be showing my solution in &lt;code&gt;nginx&lt;&#x2F;code&gt;. You can,
almost certainly, figure out a way of doing exactly the same thing with any other
decent reverse proxy software.&lt;&#x2F;p&gt;
&lt;p&gt;To create a cache for my forge, i add the following line to &lt;code&gt;&#x2F;etc&#x2F;nginx.conf&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;nginx&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;proxy_cache_path&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;var&#x2F;cache&#x2F;nginx&#x2F;forge&#x2F; levels=1:2 keys_zone=forgecache:100m;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That will create a 2-level cache called &lt;code&gt;forgecache&lt;&#x2F;code&gt; that will hold &lt;attr&gt; &lt;span title=&quot;(past me, no!!! you stupid inattentive mutt!!)&quot;&gt;&lt;del&gt;100MB of data&lt;&#x2F;del&gt;&lt;&#x2F;span&gt; 100MB of in-memory index data
for a cache
located at &lt;code&gt;&#x2F;var&#x2F;cache&#x2F;nginx&#x2F;forge&lt;&#x2F;code&gt;. i create the directory and make &lt;code&gt;www-data&lt;&#x2F;code&gt;
its owner and group.&lt;&#x2F;p&gt;
&lt;p&gt;In &lt;code&gt;&#x2F;etc&#x2F;nginx&#x2F;sites-enabled&#x2F;vcinfo-git.conf&lt;&#x2F;code&gt;, where my git forge’s site
configuration sits, i have a &lt;code&gt;location&lt;&#x2F;code&gt; block that serves the whole root of the
service, which i modify thusly:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;nginx&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;location&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; &#x2F; &lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    proxy_cache&lt;&#x2F;span&gt;&lt;span&gt; forgecache;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    proxy_buffering&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; on&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    proxy_cache_valid&lt;&#x2F;span&gt;&lt;span&gt; any &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1h&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    add_header&lt;&#x2F;span&gt;&lt;span&gt; X-Cached $upstream_cache_status;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    expires&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1h&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    proxy_ignore_headers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Set-Cookie&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    proxy_hide_header&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Set-Cookie&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # more stuff...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That configuration does several things: it turns on caching and buffering at
the proxy
(&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;nginx.org&#x2F;en&#x2F;docs&#x2F;http&#x2F;ngx_http_proxy_module.html#proxy_buffering&quot;&gt;&lt;code&gt;proxy_buffering&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;),
telling it to use &lt;code&gt;forgecache&lt;&#x2F;code&gt;
(&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;nginx.org&#x2F;en&#x2F;docs&#x2F;http&#x2F;ngx_http_proxy_module.html#proxy_cache&quot;&gt;&lt;code&gt;proxy_cache&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;)
and keep any page valid for an hour
(&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;nginx.org&#x2F;en&#x2F;docs&#x2F;http&#x2F;ngx_http_proxy_module.html#proxy_buffering&quot;&gt;&lt;code&gt;proxy_cache_valid&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;).
It also adds a cookie that will let you debug whether or not a query hit or
missed the cache (&lt;code&gt;add_header&lt;&#x2F;code&gt;). The &lt;code&gt;expires&lt;&#x2F;code&gt; directive adds headers telling
your visitor’s browser that the content they cache will also expire in an hour
(&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;nginx.org&#x2F;en&#x2F;docs&#x2F;http&#x2F;ngx_http_headers_module.html#expires&quot;&gt;&lt;code&gt;expires&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;).
Finally, the cache ignores any response header that sets a cookie
(&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;nginx.org&#x2F;en&#x2F;docs&#x2F;http&#x2F;ngx_http_proxy_module.html#proxy_ignore_headers&quot;&gt;&lt;code&gt;proxy_ignore_headers&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;,
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;nginx.org&#x2F;en&#x2F;docs&#x2F;http&#x2F;ngx_http_proxy_module.html#proxy_hide_header&quot;&gt;&lt;code&gt;proxy_hide_header&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;),
to attempt to remove any page that could be customized for a user once they log
in.&lt;&#x2F;p&gt;
&lt;div class=&quot;co-container&quot;&gt;
&lt;div class=&quot;callout warning&quot;&gt;
&lt;p&gt;&lt;span&gt; &lt;strong&gt;EDIT 2026-03-19&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;As it turns out, &lt;code&gt;proxy_ignore_headers&lt;&#x2F;code&gt; on &lt;code&gt;Set-Cookie&lt;&#x2F;code&gt; is a &lt;strong&gt;catastrophic&lt;&#x2F;strong&gt; idea. Digging into
the documentation, you can find out after two or three indirections that, by default, caching is disabled if the &lt;code&gt;Set-Cookie&lt;&#x2F;code&gt;
header is present. By ignoring it, i essentially told nginx, “hey, please, &lt;strong&gt;cache my logged in pages!!&lt;&#x2F;strong&gt;”.
The correct way to do what i want here is to remove &lt;code&gt;proxy_ignore_headers&lt;&#x2F;code&gt; and &lt;code&gt;proxy_hide_header&lt;&#x2F;code&gt; (it’s useless on &lt;code&gt;Set-Cookie&lt;&#x2F;code&gt; by default - again, nginx will not
cache those pages). The result with that configuration is the same however: caching pages when bots only access each URL once is useless.
Also, you do not need &lt;code&gt;100m&lt;&#x2F;code&gt; of cache index data. Holy fuck. That is way too much. 5 Megabytes is already enough.
&lt;&#x2F;span&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;The result? &lt;strong&gt;Caching was a disaster&lt;&#x2F;strong&gt;, predictably so. Caching works when the
same resource is repeatedly queried, like with page assets, JavaScript, style
sheets, etc. In this case, the thousands of actors querying my forge are
coordinated, somehow, never (or rarely) query the same resource twice, and only
download the raw HTML of the web pages.&lt;&#x2F;p&gt;
&lt;p&gt;Worse, caching messed up the display of authenticated pages. The snippets above
are not enough to delineate between an authenticated session and an
unauthenticated one, and it broke my forge so badly that i had to disable
caching and enable the next layer early on &lt;code&gt;2025-11-17&lt;&#x2F;code&gt;, or i just could not
use my forge.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Rate-Limiting_on_the_Proxy&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Rate-Limiting_on_the_Proxy&quot; aria-label=&quot;Anchor link for: Rate-Limiting_on_the_Proxy&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Rate-Limiting on the Proxy&lt;&#x2F;h2&gt;
&lt;p&gt;The next layer of protection simply consisted in enabling a global rate-limit on
the most-hit repositories:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;nginx&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;limit_req_zone&lt;&#x2F;span&gt;&lt;span&gt; wholeforge zone=wholeforge:10m rate=3r&#x2F;s;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;server&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;	location ^~&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBEDFF;&quot;&gt; (&#x2F;alopexlemoni&#x2F;GenderDysphoria.fyi|&#x2F;oror&#x2F;necro|&#x2F;Lymkwi&#x2F;linux|&#x2F;vc-archival&#x2F;youtube-dl-original|&#x2F;reibooru&#x2F;reibooru) &lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;		proxy_set_header&lt;&#x2F;span&gt;&lt;span&gt; Host $host;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;		proxy_set_header&lt;&#x2F;span&gt;&lt;span&gt; X-Real-IP $remote_addr;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;		proxy_max_temp_file_size&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 2048m&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;		limit_req&lt;&#x2F;span&gt;&lt;span&gt; zone=wholeforge nodelay;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;		proxy_pass&lt;&#x2F;span&gt;&lt;span&gt; http:&#x2F;&#x2F;&amp;lt;my actual upstream&amp;gt;&#x2F;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This was achieved in two directives. The first one, &lt;code&gt;limit_req_zone&lt;&#x2F;code&gt;, sits outside
the &lt;code&gt;server {}&lt;&#x2F;code&gt; block and defines a zone called &lt;code&gt;wholeforge&lt;&#x2F;code&gt; that stores 10MB of
state data and limits to 3 requests per second.&lt;&#x2F;p&gt;
&lt;p&gt;When this was in place, however, actually accessing the Linux repository as a
normal user (or any of the often-hit repositories) became a nightmare of waiting
and request timeouts.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Manually_Redirecting_to_a_Garbage_Generator&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Manually_Redirecting_to_a_Garbage_Generator&quot; aria-label=&quot;Anchor link for: Manually_Redirecting_to_a_Garbage_Generator&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Manually Redirecting to a Garbage Generator&lt;&#x2F;h2&gt;
&lt;p&gt;Because caching was (predictably) useless, and rate-limiting was hindering me
as well, i re-enabled the initial setup that was in place before my
experiments: manually redirecting queries to a garbage generator (in this case,
an old version of Iocaine). It’s largely based on my initial setup following
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;agate.blue&#x2F;2025&#x2F;03&#x2F;27&#x2F;Pi%C3%A9ger-les-robots-d&amp;#x27;indexation-gr%C3%A2ce-%C3%A0-nginx-et-iocaine.html#bonus-rate-limiting&quot;&gt;this tutorial in
french&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;For the purpose of this part, you do not have to know what Iocaine does precisely.
In the next section, i will present my current and final setup, with an updated
Iocaine that also includes a classifier to decide which queries are bots and
which are regular users. For now, i will present the version where i manually
chose who to return garbage to based on IP addresses.&lt;&#x2F;p&gt;
&lt;p&gt;As a little bonus, it will also include rate-limiting of those garbage-hungry
bots.&lt;&#x2F;p&gt;
&lt;p&gt;i add a file called &lt;code&gt;&#x2F;etc&#x2F;nginx&#x2F;snippets&#x2F;block_bots.conf&lt;&#x2F;code&gt; which contains:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;nginx&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; ($bot_user_agent) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    rewrite&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBEDFF;&quot;&gt; ^ &#x2F;deflagration$&lt;&#x2F;span&gt;&lt;span&gt;request_uri;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; ($bot_ip) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    rewrite&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DBEDFF;&quot;&gt; ^ &#x2F;deflagration$&lt;&#x2F;span&gt;&lt;span&gt;request_uri;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;location&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; &#x2F;deflagration &lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    limit_req&lt;&#x2F;span&gt;&lt;span&gt; zone=bots nodelay;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    proxy_set_header&lt;&#x2F;span&gt;&lt;span&gt; Host $host;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    proxy_pass&lt;&#x2F;span&gt;&lt;span&gt; &amp;lt;garbage upstream&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This will force any query categorized as &lt;code&gt;bot_user_agent&lt;&#x2F;code&gt; or &lt;code&gt;bot_ip&lt;&#x2F;code&gt; to be
routed through to a different upstrea which serves garbage. That upstream is
also protected by rate-limiting on a zone called &lt;code&gt;bots&lt;&#x2F;code&gt; which is defined in the
next bit of code. This snippet is actually meant to be included in your &lt;code&gt;server {}&lt;&#x2F;code&gt;
block using the &lt;code&gt;include&lt;&#x2F;code&gt; directive.&lt;&#x2F;p&gt;
&lt;p&gt;i then add the following in &lt;code&gt;&#x2F;etc&#x2F;nginx&#x2F;conf.d&#x2F;bots.conf&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;nginx&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span&gt; $&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;http_user_agent&lt;&#x2F;span&gt;&lt;span&gt; $bot_user_agent {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    default 0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # from https:&#x2F;&#x2F;github.com&#x2F;ai-robots-txt&#x2F;ai.robots.txt&#x2F;blob&#x2F;main&#x2F;robots.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;amazonbot &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;anthropic-ai  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;applebot  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;applebot-extended &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;brightbot &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;bytespider  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;ccbot &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;chatgpt-user  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;claude-web  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;claudebot &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;cohere-ai &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;cohere-training-data-crawler  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;crawlspace  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;diffbot &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;duckassistbot &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;facebookbot &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;friendlycrawler &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;google-extended &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;googleother &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;googleother-image &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;googleother-video &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;gptbot  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;iaskspider  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;icc-crawler &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;imagesiftbot  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;img2dataset &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;isscyberriskcrawler &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;kangaroo  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;meta-externalagent  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;meta-externalfetcher  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;oai-searchbot &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;omgili  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;omgilibot &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;pangubot  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;perplexitybot &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;petalbot  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;scrapy  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;semrushbot-ocob &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;semrushbot-swa  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;sidetrade &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;timpibot  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;velenpublicwebcrawler &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;webzio-extended &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    ~*&lt;&#x2F;span&gt;&lt;span&gt;youbot  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Add whatever other pattern you want down here&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;geo&lt;&#x2F;span&gt;&lt;span&gt; $bot_ip {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    default 0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Add your IP ranges here&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Rate-limiting setup for bots&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;limit_req_zone&lt;&#x2F;span&gt;&lt;span&gt; bots zone=bots:30m rate=1r&#x2F;s;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Return 429 (Too Many Requests) to slow them down&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;limit_req_status&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 429&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That bit of configuration does a mapping between the client IP and a variable
called &lt;code&gt;bot_ip&lt;&#x2F;code&gt;, and the client’s user agent and a variable called
&lt;code&gt;bot_user_agent&lt;&#x2F;code&gt;. When a known pattern listed in those blocks is found, the
corresponding variable is flipped to the provided value (here, &lt;code&gt;1&lt;&#x2F;code&gt;). Otherwise,
it stays &lt;code&gt;0&lt;&#x2F;code&gt;. Then, we define the rate-limiting zone that is used to slow down
the bots so they don’t feed on slop too fast. You will then need to install the
&lt;code&gt;http-geoip2&lt;&#x2F;code&gt; nginx module (on Debian-based distributions, something like &lt;code&gt;apt install libnginx-mod-http-geoip2&lt;&#x2F;code&gt; will do).&lt;&#x2F;p&gt;
&lt;p&gt;Once that is done, add the following line to the &lt;code&gt;server&lt;&#x2F;code&gt; block of every site
you want to protect:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;nginx&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;include&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;etc&#x2F;nginx&#x2F;snippets&#x2F;block_bots.conf;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And when you feel confident enough, roll a &lt;code&gt;nginx -t&lt;&#x2F;code&gt; and reload the unit for
&lt;code&gt;nginx&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Now, if you’re using &lt;code&gt;caddy&lt;&#x2F;code&gt; or any other reverse proxy, there are probably
similar mechanisms available. You can go and peruse the documentation of Iocaine,
or look online for specific tutorials that, i am sure, other people have made
better than i would.&lt;&#x2F;p&gt;
&lt;p&gt;Immediately after enabling it, and shoving all the IPs from Alibaba Cloud and
Huawei Cloud in the bot config file, the activity slowed down on my server.
Power usage went down to ~180W, CPU usage to rougly 60%, and it stopped making
a hellish noise.&lt;&#x2F;p&gt;
&lt;p&gt;As the stats showed earlier, however, a lot of traffic was still hitting the
server itself. Even weirder, there were still occasional spikes, every 3 hour,
that lasted about one and a half hour, where the server would whirr and
forgejo suffocate again.&lt;&#x2F;p&gt;
&lt;p&gt;Bots were still hitting my server, and there was no clear source for it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Automatically_Classifying_Bots_and_Poisoning_Them:_Iocaine_and_Nam-Shub-of-Enki&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Automatically_Classifying_Bots_and_Poisoning_Them:_Iocaine_and_Nam-Shub-of-Enki&quot; aria-label=&quot;Anchor link for: Automatically_Classifying_Bots_and_Poisoning_Them:_Iocaine_and_Nam-Shub-of-Enki&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Automatically Classifying Bots and Poisoning Them: Iocaine and Nam-Shub-of-Enki&lt;&#x2F;h2&gt;
&lt;p&gt;So far, the steps i showed so far help when a single IP is hammering at your
forge, or when someone is clearly scraping you from an Autonomous System that
you do not mind blocking. Sadly, as i’ve showed above in &lt;a href=&quot;https:&#x2F;&#x2F;vulpinecitrus.info&#x2F;blog&#x2F;guarding-git-forge-ai-scrapers&#x2F;#tab_4&quot;&gt;Table 4&lt;&#x2F;a&gt;, a
surprising amount of scraping comes from broadband addresses. i can assemble
lists of IPs as big as i want, or block entire ASNs, but i would love to have a
per-query way of determining if a query looks legitimate.&lt;&#x2F;p&gt;
&lt;p&gt;The next steps of protection will rely on categorizing a source IP based on its
the credibility of its user agent. This mechanism is
largely based on the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;iocaine.madhouse-project.org&#x2F;documentation&#x2F;3&#x2F;&quot;&gt;documentation for Iocaine
3.x&lt;&#x2F;a&gt;. &lt;small&gt;We finally
get to talk about Iocaine!&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Iocaine is a tool that traps scrapers in a maze of meaningless pages that
endlessly lead to more meaningless pages. The content of these pages is
generated using a Markov chain, based on a corpus of texts given to the
software. Iocaine (specifically all versions after 3 at least&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-v2-1-1&quot;&gt;&lt;a href=&quot;#fn-v2-1&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;) is a middleware, in
the sense that it works by being placed on the line between your reverse proxy
and the service. Your reverse proxy will first begin by redirecting traffic to
Iocaine, and, if Iocaine deems a query legitimate, it will return a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;http.cat&#x2F;421&quot;&gt;&lt;code&gt;421 Misdirected Request&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; back at your reverse-proxy. The
latter must then catch it, and use the &lt;em&gt;real&lt;&#x2F;em&gt; upstream as a fallback. If
Iocaine’s Nam-Shub-of-Enki&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-nsoe-1&quot;&gt;&lt;a href=&quot;#fn-nsoe&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; decides query came from a bogus or otherwise undesirable source, it
will happily reply &lt;code&gt;200 OK&lt;&#x2F;code&gt; and send generated garbage.&lt;&#x2F;p&gt;
&lt;p&gt;My setup lodges Iocaine 3 between nginx and my forge, following the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;iocaine.madhouse-project.org&#x2F;documentation&#x2F;3&#x2F;getting-started&#x2F;containers&#x2F;&quot;&gt;Iocaine
documentation to use the container
version&lt;&#x2F;a&gt;.
i recommend you follow it, and then add the next little things to enable
categorization statistics, and prevent the logging they’re based on from
blowing up your storage:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;In &lt;code&gt;etc&#x2F;config.d&#x2F;03-nam-shub-of-enki.kdl&lt;&#x2F;code&gt;, change the logging block to:&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;logging {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    enable #true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    classification {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        enable #true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;In &lt;code&gt;docker-compose.yaml&lt;&#x2F;code&gt;, add the following bits to limit classification
logging to 50MB:&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;services:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  iocaine:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    # The things you already have here...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    # ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    env:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      - RUST_LOG=iocaine=info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    logging:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      driver: &amp;quot;json-file&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      options:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        max-size: &amp;quot;50m&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;My checks block in Nam-Shub-of-Enki is as such:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;checks {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    disable cgi-bin-trap&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    asn {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        database-path &amp;quot;&#x2F;data&#x2F;ipinfo_lite.mmdb&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        asns &amp;quot;45102&amp;quot; &amp;quot;136907&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ai-robots-txt {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        path &amp;quot;&#x2F;data&#x2F;ai.robots.txt-robots.json&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    generated-urls {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        identifiers &amp;quot;deflagration&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    big-tech {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        enable #true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    commercial_scrapers {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        enable #true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I snatched a copy of the latest &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;ipinfo.io&#x2F;&quot;&gt;ipinfo ASN database&lt;&#x2F;a&gt; for
free and blocked AS52102 (Alibaba) and AS136907 (Huawei Clouds).&lt;&#x2F;p&gt;
&lt;p&gt;On 2025-11-18 at 00:00:29 UTC+1, i enabled Iocaine with the Nam-Shub-of-Enki
classifier in front of my whole forge. Immediately, my server was no longer
hammered. Power draw went down to just above 160W.&lt;&#x2F;p&gt;
&lt;p&gt;One problem i noticed however, while trying to deploy the artifact for this
blog post on my forge, is that Iocaine causes issues when huge &lt;code&gt;PUT&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;PATCH&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;POST&lt;&#x2F;code&gt;
requests with large bodies are piped through it: it will hang up before the
objects are entirely written. i am trying to figure out a way of only redirecting
&lt;code&gt;HEAD&lt;&#x2F;code&gt; and &lt;code&gt;GET&lt;&#x2F;code&gt; requests to Iocaine in nginx, like is done in the Caddy example
of the Iocaine documentation.&lt;&#x2F;p&gt;
&lt;p&gt;What i ended up settling on requires a bit of variable mapping. At the start of
your site configuration, before the &lt;code&gt;server {}&lt;&#x2F;code&gt; block:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;map $request_method $upstream_location {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	GET	&amp;lt;iocaine upstream&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	HEAD	&amp;lt;iocaine upstream&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	default	&amp;lt;your actual upstream&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;map $request_method $upstream_log {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	GET	bot_access;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	HEAD	bot_access;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	default	access;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, in the block that does the default location, write:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	location &#x2F; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	    proxy_cache off;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	    access_log &#x2F;var&#x2F;log&#x2F;nginx&#x2F;$upstream_log.log combined;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	    proxy_intercept_errors on;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	    error_page 421 = @fallback;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	    proxy_set_header Host $host;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	    proxy_set_header X-Real-IP $remote_addr;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	    proxy_pass http:&#x2F;&#x2F;$upstream_location;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That is, replace the upstream in &lt;code&gt;proxy_pass&lt;&#x2F;code&gt; with the upstream decided by the
variable mapping, and, while we’re at it, use &lt;code&gt;$upstream_log&lt;&#x2F;code&gt; to know which log
will be the final one for that request. i differentiate between &lt;code&gt;bot_access.log&lt;&#x2F;code&gt;
and &lt;code&gt;access.log&lt;&#x2F;code&gt; to gather my statistics, so the difference matters to me. Change
the variables to suit the way you do it (or remove it, if you don’t distinguish
clients in your log files).&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Monitoring_Iocaine&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Monitoring_Iocaine&quot; aria-label=&quot;Anchor link for: Monitoring_Iocaine&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Monitoring Iocaine&lt;&#x2F;h1&gt;
&lt;p&gt;Currently, on 2025-11-30 at 16:33:00 UTC+1, Iocaine has served 38.16GB of garbage.
Over the past hour, 152.11MB of such data was thrown back at undesirable visitors.
3.39GB over the past day, 22.22GB over the past week. You can get the snippet
that describes my Iocaine-specific Grafana views &lt;a href=&quot;https:&#x2F;&#x2F;vulpinecitrus.info&#x2F;blog&#x2F;guarding-git-forge-ai-scrapers&#x2F;.&#x2F;grafana-panel.json&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The vast majority of undesirable queries come from Claude, OpenAI, and
Disguised Bots. Claude and OpenAI are absolutely gluttonous, and, once they
have access to a ton of pages, they will greedily flock to fetch them like
pigeons being fed breadcrumbs laced with strychnine.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;vulpinecitrus.info&#x2F;blog&#x2F;guarding-git-forge-ai-scrapers&#x2F;hits-by-ruleset.png&quot; title=&quot;Graph%20showing%20time%20series%20of%20bot%20request%20classification,%20with%20peaks%20of%20requests,%20background%20noise,%20and%20a%20constant%20level%20of%20AI%20scrapers&quot; alt=&quot;Hits by Ruleset on my Grafana&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;AI bot scrapers (&lt;code&gt;ai.robots.txt&lt;&#x2F;code&gt;) maintain a constant 920~930 query per minute
(15-ish QPS) over the 6 domains i have protected with Iocaine, including the
forge.&lt;&#x2F;p&gt;
&lt;p&gt;There is also a low hum of a mix of commercial scrapers (~1 request every two
second), big tech crawlers (Facebook, Google, etc, about 2QPS or 110 query&#x2F;min),
and, especially, fake browsers.&lt;&#x2F;p&gt;
&lt;p&gt;Classifying fake browsers is where Iocaine really shines, specifically thanks
to the classifiers implemented via Nam-Shub-of-Enki. The faked bots classifier
detects the likelihood that the user agent reported by the client is bullshit,
generated from a list of technologies mashed together. For example, if your
client reports a user agent for a set of software that never supported HTTP2,
or never actually existed together, or &lt;em&gt;is not even released yet&lt;&#x2F;em&gt;, it will get
flagged. Think, for example, Windows NT 4 running Chrome, pretending to be
able to do TLS1.3.&lt;&#x2F;p&gt;
&lt;p&gt;The background-noise level of such queries is usually 140~160 queries per minute
(or 2~3 QPS). However, notice those spikes in the graph above?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#&quot; aria-label=&quot;Anchor link for: &quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
The Salves of Queries&lt;&#x2F;h2&gt;
&lt;p&gt;For a while during my experiments i noticed those pillars of queries. My
general nginx statistics would show a sharp increase of connections, with an
iniital ramp-up, and a stable-ish plateau lasting about one and a half hour,
before suddenly stopping. It would then repeat again, roughly three hours later.&lt;&#x2F;p&gt;
&lt;p&gt;Between October 29th and November 19th, and on November 28th, these spikes would
constantly show up. As soon as i got Iocaine statistics running, it would flag
all of those queries as faked browsers.&lt;&#x2F;p&gt;
&lt;p&gt;i investigated those spikes in particular, because they baffled and scared me:
the regularity with which they probed me, and the sharpness of the ramp-up and
halts, made me afraid that someone, somewhere, was organizing thousands of IPs
to specifically take turns at probing websites. i have not reached any solid
conclusions, beyond the following:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The initial phase of an attack wave begins with a clear exponential ramp-up&lt;&#x2F;li&gt;
&lt;li&gt;The ramp-up stops when the server starts either throwing errors, or the
response latency reaches a given threshold&lt;&#x2F;li&gt;
&lt;li&gt;Every wave of attack lasts roughly one hour and a half&lt;&#x2F;li&gt;
&lt;li&gt;An individual IP will often contribute no more than one query, but it can
reach 50 to 60 queries per IP&lt;&#x2F;li&gt;
&lt;li&gt;The same 15 or so ASN keep showing up, with five regular leaders in IP count:
&lt;ol&gt;
&lt;li&gt;AS212238: Datacamp Limited&lt;&#x2F;li&gt;
&lt;li&gt;AS3257: GTT Communications&lt;&#x2F;li&gt;
&lt;li&gt;AS9009: M247 Europe SRL&lt;&#x2F;li&gt;
&lt;li&gt;AS203020: HostRoyale Technologies Pvt Ltd&lt;&#x2F;li&gt;
&lt;li&gt;AS210906: UAB “Bite Lietuva” (a Lithuanian ISP)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;All of those as service providers. My working theory at the moment is that
someone registered thousands of cheap servers in many different companies, and
are selling access to them as web proxies for scraping and scanning. i will
probably write something up later when i have properly investigated that
specific phenomenon.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;-1&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#-1&quot; aria-label=&quot;Anchor link for: -1&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Conclusion&lt;&#x2F;h1&gt;
&lt;p&gt;Self-hosting anything that is deemed “content” openly on the web in 2025 is
a battle of attrition between you and forces who are able to buy tens of
thousands of proxies to ruin your service for data they can resell.&lt;&#x2F;p&gt;
&lt;p&gt;This is depressing. Profoundly depressing. i look at the statistics board for
my reverse-proxy and i never see less than 96.7% of requests classified as bots
at any given moment. The web is filled with crap, bots that pretend to be real
people to flood you. All of that because i want to have my little corner of the
internet where i put my silly little code for other people to see.&lt;&#x2F;p&gt;
&lt;p&gt;i have to learn to protect myself from industrial actors in order to put anything
online, because anything a person makes is valuable, and that value will be
sucked dry by every tech giant to be emulsified, liquified, strained, and
ultimately inexorably joined in an unholy mesh of learning weights.&lt;&#x2F;p&gt;
&lt;p&gt;This experience has rather profoundly radicalized the way i think about
technology. Sanitized content can be chewed on and shat out by companies from
training, but their AI tools will never swear. They will never use a slur. They
will never have a revolutionary thought. Despite being amalgamation of shit
rolled up in the guts of the dying capitalist society, they are sanitized to
hell and beyond.&lt;&#x2F;p&gt;
&lt;p&gt;The developer of Iocaine &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;come-from.mad-scientist.club&#x2F;@algernon&#x2F;statuses&#x2F;01KAY04QH0A3AAT9P0JD0H5FQH&quot;&gt;put it best&lt;&#x2F;a&gt;
when explaining why Iocaine has absolutely unhinged identifiers
(such as &lt;code&gt;SexDungeon&lt;&#x2F;code&gt;, &lt;code&gt;PipeBomb&lt;&#x2F;code&gt;, etc) is that they will all trigger “safeguard”
mechanisms in commercial AI tools: absolutely no coding agent will accept
analyzing and explaining code where the memory allocator’s free function is
called &lt;code&gt;liberate_palestine&lt;&#x2F;code&gt;. i bet that if i described, in graphic details, in
the comments of this page, the different ways being a furry intersects with my
sexuality, that no commercial scraper would even dare ingest this page.&lt;&#x2F;p&gt;
&lt;!-- Curious bee, eh? --&gt;
&lt;p&gt;Fuck tech companies. Fuck “AI”. Fuck the corporate web.&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-qos&quot;&gt;
&lt;p&gt;i could’ve put QOS in place to limit that traffic; but that would only
have been a bandaid solution, and caused massive congestion because of traffic
shaping anyways. &lt;a href=&quot;#fr-qos-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-cache-failure&quot;&gt;
&lt;p&gt;Caching alone proved so inefficient that i had to enable the
next layer before the day ended, because the server was on its knees and nothing
visibly improved with just caching alone. &lt;a href=&quot;#fr-cache-failure-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-redacted&quot;&gt;
&lt;p&gt;“Whoops! i did not know that was still public. Yikes! That’s doxxing me!”, i said, while gathering those stats. &lt;a href=&quot;#fr-redacted-1&quot;&gt;↩&lt;&#x2F;a&gt; &lt;a href=&quot;#fr-redacted-2&quot;&gt;↩2&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-gtt&quot;&gt;
&lt;p&gt;Like, seriously. i spent five minutes on they home page trying to figure out if they were a tier-2 ISP, a datacenter
infrastructure provider, an IT management company, a hosting company, and i have &lt;em&gt;no idea&lt;&#x2F;em&gt;. Their home page is filled with
impenetrable corporate jargon. If you want to know what they do, you have to look them up elsewhere. &lt;a href=&quot;#fr-gtt-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-v2-1&quot;&gt;
&lt;p&gt;Initially, until 2025-11-15, i was using Iocaine 2.1, which required
that you manually redirect traffic to it. The classifiers and request handlers
that required Iocaine to be in the line of traffic were added in later versions. &lt;a href=&quot;#fr-v2-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-nsoe&quot;&gt;
&lt;p&gt;See, i don’t really understand to this day of Nam-Shub-of-Enki is a
classifier, a request handler, or a set of classifying rules. To me, it’s a
classifier framework, but i am not sure. Iocaine is great, but its documentation
is a bit all over the place at the moment (and commits a couple cardinal sins
of documentation writing, like, for example, mixing documentation for developers
with documentation for the users). &lt;a href=&quot;#fr-nsoe-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Deploying my Zola Blog Automatically</title>
        <published>2025-08-02T00:00:00+00:00</published>
        <updated>2025-08-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/my-zola-deployment/"/>
        <id>https://vulpinecitrus.info/blog/my-zola-deployment/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/my-zola-deployment/">&lt;p&gt;i feel like it’s obligatory, at some point, on any blog that talks about tech,
to have a post that goes “oh here’s how i deploy it by the way”. Now is my
turn, i guess? But this isn’t simply ‘how i deploy’, and more of “how i
perfected my deployment to go from 11 minutes of CI to about one and a half,
and what i learned in the process”. In the end, i guess, this is more of a post
about CI&#x2F;CD.&lt;&#x2F;p&gt;
&lt;p&gt;If you want the full file as it is, you can go &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;Lymkwi&#x2F;blog-vulpinecitrus&#x2F;src&#x2F;commit&#x2F;f5360a2923a02ea7561c09cb0aeb009ec963f69c&#x2F;.forgejo&#x2F;workflows&#x2F;deploy.yaml&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;My_Environment&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#My_Environment&quot; aria-label=&quot;Anchor link for: My_Environment&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
My Environment&lt;&#x2F;h1&gt;
&lt;p&gt;There’s only one thing worse than making CI&#x2F;CD pass: debugging it.&lt;&#x2F;p&gt;
&lt;p&gt;Continuous Integration and Delivery is a practice in devops (remember when that
was &lt;em&gt;the&lt;&#x2F;em&gt; buzzword?) that consists in automating checks and deployment in a
development forge. It will also refer to the tools that allow you to do such
automation.&lt;&#x2F;p&gt;
&lt;p&gt;My environment is as follows:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;git forge running Forgejo with “actions” (the Forgejo slang for CI&#x2F;CD, taken
from GitHub actions)&lt;&#x2F;li&gt;
&lt;li&gt;A blog written with the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;getzola.org&#x2F;&quot;&gt;Zola&lt;&#x2F;a&gt; engine&lt;&#x2F;li&gt;
&lt;li&gt;A web server that serves flat files (your browser likely interacted with it to read this)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;There is additional complexity surrounding the forge and how its actions run:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;There are 5 runners on my forge server&lt;&#x2F;li&gt;
&lt;li&gt;All runners are docker containers, which can themselves spawn docker containers&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;It happened in the past that i needed features not available yet in Zola, or
encountered bugs that were not yet fixed in the latest release. If i used
pre-made docker images, i would have to make them myself, which requires a lot
of work behind the scenes: manually connecting to the host, pulling a docker
image, running it, installing the necessary version of Rust if not already
present, then the version of Zola i want, then tagging it. Even when this is
all automated in a &lt;code&gt;Dockerfile&lt;&#x2F;code&gt;, this way of doing things requires backend
admin access, which i cannot guarantee everyone has, and i cannot guarantee i
would have on another Forgejo instance.&lt;&#x2F;p&gt;
&lt;p&gt;So, another condition on the infrastructure:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;i am not using pre-made docker images that already contain Zola&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h1 id=&quot;The_Basic_Version&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#The_Basic_Version&quot; aria-label=&quot;Anchor link for: The_Basic_Version&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
The Basic Version&lt;&#x2F;h1&gt;
&lt;p&gt;In DevOps, a “workflow” is a set of different “jobs” that are themselves sequences
of steps that run in a given environment. You can have multiple workflows in a
repository, multiple jobs in a workflow (with conditions as to who runs before
what and such), and, of course, multiple steps per job. My repository will have
one workflow, with one job called &lt;code&gt;deploy-website&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;i start by creating a very simple YAML file in &lt;code&gt;.forgejo&#x2F;workflows&#x2F;&lt;&#x2F;code&gt; at the
root of my directory. The skeleton of the workflow file is as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Deploy Vulpine Citrus&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;on&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; push&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  build-website&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    runs-on&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ubuntu-22.04&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    container&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;      image&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; rust:latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    steps&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Install node&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;          apt update &amp;amp;&amp;amp; apt install --yes nodejs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Check out sources&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        uses&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; actions&#x2F;checkout@v3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Checkout submodules&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;        run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; git submodule update --init --recursive&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There are various points to discuss in the skeleton already:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;All of my runners are tagged as ‘ubuntu-22.04’ (meaning that, by default, they
would run your action in a Docker container running an Ubuntu 22.04 image)&lt;&#x2F;li&gt;
&lt;li&gt;i give my action a name, and tell it to run every time something is pushed to
the repo&lt;&#x2F;li&gt;
&lt;li&gt;Because other projects already running on the forge use a Rust image, and
because i do not depend on a given minimum version, i make the runner deploy
my job in a &lt;code&gt;rust:latest&lt;&#x2F;code&gt; container&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Complication #1&lt;&#x2F;strong&gt;: &lt;code&gt;rust:latest&lt;&#x2F;code&gt; does not include &lt;code&gt;node&lt;&#x2F;code&gt; by default, which
is necessary for the actions that pull your sources (&lt;em&gt;for some reason&lt;&#x2F;em&gt;), so it
is installed before anything else&lt;&#x2F;li&gt;
&lt;li&gt;My blog repo uses a submodule, so it gets deployed&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;Installing_Zola&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Installing_Zola&quot; aria-label=&quot;Anchor link for: Installing_Zola&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Installing Zola&lt;&#x2F;h2&gt;
&lt;p&gt;Now onto the other steps: i want to install Zola using &lt;code&gt;cargo&lt;&#x2F;code&gt;, so i add the
following step:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Install Zola&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; cargo install --locked --git https:&#x2F;&#x2F;github.com&#x2F;getzola&#x2F;zola.git --tag v0.20.0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The option &lt;code&gt;--locked&lt;&#x2F;code&gt; makes us respect all dependency versions listed in the
&lt;code&gt;Cargo.lock&lt;&#x2F;code&gt; file from the repo. This is recommended, because dependencies might
have new versions that were not proven to build correctly yet (some people just
break semantic versioning, sometimes)&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-cargoforce-1&quot;&gt;&lt;a href=&quot;#fn-cargoforce&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Building_the_Blog&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Building_the_Blog&quot; aria-label=&quot;Anchor link for: Building_the_Blog&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Building the Blog&lt;&#x2F;h2&gt;
&lt;p&gt;Once &lt;code&gt;zola&lt;&#x2F;code&gt; is an executable that can be run, we can run it:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Build site&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; zola build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And now, the flat web files are available in &lt;code&gt;.&#x2F;public&#x2F;&lt;&#x2F;code&gt;. And we need to
transfer them now… somehow?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;It_Gets_Weird:_Transferring_to_the_Server&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#It_Gets_Weird:_Transferring_to_the_Server&quot; aria-label=&quot;Anchor link for: It_Gets_Weird:_Transferring_to_the_Server&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
It Gets Weird: Transferring to the Server&lt;&#x2F;h2&gt;
&lt;p&gt;Transferring files to the server is done this way: the old blog directory on the
server is wiped, and the entire &lt;code&gt;public&#x2F;&lt;&#x2F;code&gt; folder from the pipeline is transferred
via SSH to re-populate it.&lt;&#x2F;p&gt;
&lt;p&gt;We need to make use of a feature in Forgejo Actions called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;forgejo.org&#x2F;docs&#x2F;v1.21&#x2F;user&#x2F;actions&#x2F;#secrets&quot;&gt;Secrets&lt;&#x2F;a&gt;. Secrets allow you to create protected
variables that your actions can use but that cannot be read again. In my setup,
i create two such variables: &lt;code&gt;CONNECT_KEY&lt;&#x2F;code&gt; and &lt;code&gt;REMOTE&lt;&#x2F;code&gt;. The former is an SSH
private key, and the latter is a remote URL in the format of &lt;code&gt;user@host&lt;&#x2F;code&gt;. That
user has write permissions on the blog directory.&lt;&#x2F;p&gt;
&lt;p&gt;Then, after way too much engineering, we have this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Upload to server&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    echo &amp;quot;${{ secrets.CONNECT_KEY }}&amp;quot; &amp;gt;&amp;gt; key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    chmod 600 key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    ssh -o StrictHostKeyChecking=no -o IdentityFile=key ${{ secrets.REMOTE }} &amp;quot;rm -rf &#x2F;var&#x2F;www&#x2F;vulpinecitrus&#x2F;*&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    scp -o StrictHostKeyChecking=no -o IdentityFile=key -r .&#x2F;public&#x2F;* ${{ secrets.REMOTE }}:&#x2F;var&#x2F;www&#x2F;vulpinecitrus&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    ssh -i key ${{ secrets.REMOTE }} &amp;quot;chown -R www-data:www-data &#x2F;var&#x2F;www&#x2F;vulpinecitrus&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    rm key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Multiple things to say here:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The file &lt;code&gt;public.zip&lt;&#x2F;code&gt; is created, containing the tree of the blog repo&lt;&#x2F;li&gt;
&lt;li&gt;The secret value &lt;code&gt;CONNECT_KEY&lt;&#x2F;code&gt; is written to a file called &lt;code&gt;key&lt;&#x2F;code&gt;, and its
permissions are set (to &lt;code&gt;0o600&lt;&#x2F;code&gt;) such that SSH does not complain that someone
other than the owner of the file can read its contents or write to it&lt;&#x2F;li&gt;
&lt;li&gt;Using &lt;code&gt;ssh&lt;&#x2F;code&gt;, i begin by deleting the entirety of ‘&#x2F;var&#x2F;www&#x2F;vulpinecitrus&#x2F;’,
where the old blog tree resides&lt;&#x2F;li&gt;
&lt;li&gt;Using &lt;code&gt;scp&lt;&#x2F;code&gt;, i move all the files from &lt;code&gt;public&#x2F;&lt;&#x2F;code&gt; to the folder that was
just wiped&lt;&#x2F;li&gt;
&lt;li&gt;Ownership information is set so that &lt;code&gt;www-data&lt;&#x2F;code&gt; is both the owner and the
group owner for the new files&lt;&#x2F;li&gt;
&lt;li&gt;All the SSH commands use &lt;code&gt;ScriptHostKeyChecking=no&lt;&#x2F;code&gt;, which is technically
&lt;em&gt;terrible&lt;&#x2F;em&gt;, because it bypasses first-time fingerprint checking. This was
added because the pipeline Docker, since it is a ‘fresh’ install, does
not know the remote server. If you want to be more secure, you can add a
&lt;code&gt;REMOTE_FINGERPRINT&lt;&#x2F;code&gt; variable, and add it to &lt;code&gt;~&#x2F;.ssh&#x2F;known_hosts&lt;&#x2F;code&gt; prior to
opening remote connections&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;IdentityFile=key&lt;&#x2F;code&gt; (or &lt;code&gt;-i&lt;&#x2F;code&gt; for &lt;code&gt;ssh&lt;&#x2F;code&gt;) tells the programs to use &lt;code&gt;key&lt;&#x2F;code&gt; as the private
identity key presented to authenticate with the server&lt;&#x2F;li&gt;
&lt;li&gt;The key, of course, is destroyed by the action script&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;And with this, we have a very basic action: it gets the sources, builds Zola,
builds the site, and deploys it. But it has things i would want to improve on:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The website gets updated every time something is pushed, including files that
should not trigger rebuilds&lt;&#x2F;li&gt;
&lt;li&gt;Only the &lt;code&gt;main&lt;&#x2F;code&gt; branch is deployed and should trigger the CI&#x2F;CD&lt;&#x2F;li&gt;
&lt;li&gt;Having a copy of the blog tree that can be downloaded as an archive from the
action would help debug future problems&lt;&#x2F;li&gt;
&lt;li&gt;On the server running Forgejo, building Zola takes &lt;strong&gt;8 minutes&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h1 id=&quot;Improvement_1:_Conditional_Building&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Improvement_1:_Conditional_Building&quot; aria-label=&quot;Anchor link for: Improvement_1:_Conditional_Building&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Improvement 1: Conditional Building&lt;&#x2F;h1&gt;
&lt;p&gt;Forgejo Actions borrows its description language from GitHub Actions, which
allow for &lt;em&gt;conditional building&lt;&#x2F;em&gt;. You can specify a regex or set of regexes and
a branch name with the &lt;code&gt;push&lt;&#x2F;code&gt; event type that correspond to the desired triggers.&lt;&#x2F;p&gt;
&lt;p&gt;In my case, this is:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;on&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  push&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    paths&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config.toml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; static&#x2F;**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; sass&#x2F;**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; templates&#x2F;**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; themes&#x2F;**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; content&#x2F;**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; .forgejo&#x2F;workflows&#x2F;deploy.yaml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    branches&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The action will run again if something is pushed on &lt;code&gt;main&lt;&#x2F;code&gt; that is either: a
change in configuration, a new static file, a change in CSS, a change to the
templates, a change to the theme files, a change to content (posts), or the
workflow file itself.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Improvement_2:_Artifacts&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Improvement_2:_Artifacts&quot; aria-label=&quot;Anchor link for: Improvement_2:_Artifacts&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Improvement 2: Artifacts&lt;&#x2F;h1&gt;
&lt;p&gt;Artifacts are blobs of data generated by CI&#x2F;CD. In my case, i want a copy of the
deployed blog root in ZIP file so i can debug it in case something does not make
sense in the hierarchy of files. Uploading Artifacts on Forgejo Actions is a
pretty janky process, but i figured out how to make it work.&lt;&#x2F;p&gt;
&lt;p&gt;To understand that, however, we need to go on a small tangent about all of these
step scripts, like &lt;code&gt;actions&#x2F;checkout@v3&lt;&#x2F;code&gt;. This is GitHub Actions syntax, which
originally meant “Take the code at branch &lt;code&gt;v3&lt;&#x2F;code&gt; of the repo &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;actions&#x2F;checkout&quot;&gt;&lt;code&gt;https:&#x2F;&#x2F;github.com&#x2F;actions&#x2F;checkout&#x2F;&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, and run it”. The action available
for saving Artifacts, &lt;code&gt;upload-artifact@v4&lt;&#x2F;code&gt;, is capable of saving a file or set
of files. In my experience with &lt;code&gt;@v3&lt;&#x2F;code&gt; on Forgejo, it was more reliable to ZIP
the files yourself and save them. The fourth version of that action, however,
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;code.forgejo.org&#x2F;forgejo&#x2F;runner&#x2F;src&#x2F;branch&#x2F;main&#x2F;RELEASE-NOTES.md#3-4-0&quot;&gt;removed compatibility with anything that isn’t GitHub&lt;&#x2F;a&gt;. While Forgejo actions are not
retrieved from GitHub, a lot of them are simply mirrors of the GitHub version.
As a result, when using &lt;code&gt;actions&#x2F;upload-artifact@v4&lt;&#x2F;code&gt; or &lt;code&gt;actions&#x2F;download-artifact@v4&lt;&#x2F;code&gt;
(which can be used for two unrelated CI action scripts to exchange files; that’s
another use of artifacts), you have to use the version available at &lt;code&gt;https:&#x2F;&#x2F;code.forgejo.org&#x2F;forgejo&#x2F;&lt;&#x2F;code&gt;. Because of how actions work, you can absolutely just specify a
URL instead of &lt;code&gt;actions&#x2F;whatever&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Next, the action will need a unique name for the artifact. In our case, i want
to call it &lt;code&gt;vulpinecitrus-{branch}-{short commit ID}.zip&lt;&#x2F;code&gt;. With the fact that i
need to zip the files (and &lt;code&gt;zip&lt;&#x2F;code&gt; is not installed by default), this gives us:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Install node &amp;amp; zip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    apt update &amp;amp;&amp;amp; apt install --yes nodejs zip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Compress&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; zip -r public.zip public&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Create file name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    forge_ref=${{ gitea.ref }}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    echo &amp;quot;ART_FILENAME=vulpinecitrus-${forge_ref#refs&#x2F;heads&#x2F;}-$(git rev-parse --short ${{ gitea.sha }})&amp;quot; &amp;gt;&amp;gt; &amp;quot;$GITHUB_ENV&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Save as artifact&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  uses&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; https:&#x2F;&#x2F;data.forgejo.org&#x2F;forgejo&#x2F;upload-artifact@v4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  with&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ${{ env.ART_FILENAME }}.zip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    path&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; public.zip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here’s how it goes:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;i add &lt;code&gt;zip&lt;&#x2F;code&gt; to the packages that are installed at the start&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;code&gt;public&#x2F;&lt;&#x2F;code&gt; directory is compressed&lt;&#x2F;li&gt;
&lt;li&gt;A step is added to create a variable in the environment of the build script
called &lt;code&gt;ART_FILENAME&lt;&#x2F;code&gt;. Variables are created by appending them at a location
pointed to by &lt;code&gt;$GITHUB_ENV&lt;&#x2F;code&gt; (to this day, i do not know if that name has been
changed yet for Forgejo, but the GitHub version works). The value placed in
there is a combination of the various things i wanted: the short commit hash
(&lt;code&gt;git rev-parse --short ${{ gitea.sha }}&lt;&#x2F;code&gt;), and the name of the branch
(&lt;code&gt;${{ gitea.ref }}&lt;&#x2F;code&gt; without the leading &lt;code&gt;refs&#x2F;heads&#x2F;&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;The variable &lt;code&gt;ART_FILENAME&lt;&#x2F;code&gt; variable is later accessed in the &lt;code&gt;env&lt;&#x2F;code&gt; object&lt;&#x2F;li&gt;
&lt;li&gt;Finally, we save the artifact, uploading &lt;code&gt;public.zip&lt;&#x2F;code&gt; and calling it &lt;code&gt;${{ env.ART_FILENAME }}.zip&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;As you can see, the layers of software history are unraveling. When this was
written originally, Forgejo had barely forked from Gitea, meaning that all the
CI&#x2F;CD infrastructure still used &lt;code&gt;gitea&lt;&#x2F;code&gt; as a namespace for variables. There is
also leftovers of GitHub here and there.&lt;&#x2F;p&gt;
&lt;p&gt;Now, i do not remember everything i did on the server side to actually get
artifacts running. Memory tells me that there is some configuration that needs
changing, but chances are that it is already available on your instance if your
admin has enabled actions at all.&lt;&#x2F;p&gt;
&lt;p&gt;Adding artifacts to the steps adds fourteen seconds to my workflow. That is not
a lot for me, but if you find that it takes too long, you can always place the
part that transfers to the remote server first.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Improvement_3:_Caching_Zola_Build&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Improvement_3:_Caching_Zola_Build&quot; aria-label=&quot;Anchor link for: Improvement_3:_Caching_Zola_Build&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Improvement 3: Caching Zola Build&lt;&#x2F;h1&gt;
&lt;p&gt;With all of that said, building Zola still takes ages. CI&#x2F;CD systems introduced
caches to deal with this kind of problem, so let’s use them. This will be pretty
straightforward, but i will use one trick.&lt;&#x2F;p&gt;
&lt;p&gt;We will initially try to retrieve a cache called &lt;code&gt;zola-{ zola version }&lt;&#x2F;code&gt; before
building. To do so, a new environment variable is added to the workflow, so that
we can consistently modify the desired version everywhere in the script&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-zolav-1&quot;&gt;&lt;a href=&quot;#fn-zolav&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. This is
placed at the root of the YAML file, under the &lt;code&gt;name&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;env&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  ZOLA_VERSION&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; v0.20.0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, we attempt to retrieve the cache in our steps:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Retrieve Zola cache&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  uses&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; actions&#x2F;cache&#x2F;restore@v4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  with&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    path&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &#x2F;usr&#x2F;local&#x2F;cargo&#x2F;registry&#x2F;index&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &#x2F;usr&#x2F;local&#x2F;cargo&#x2F;registry&#x2F;cache&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &#x2F;usr&#x2F;local&#x2F;cargo&#x2F;bin&#x2F;zola&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &#x2F;usr&#x2F;local&#x2F;cargo&#x2F;git&#x2F;db&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    key&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; zola-${{ env.ZOLA_VERSION }}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;i am saving the registry cache and index, the database of crates, and the binary
&lt;code&gt;zola&lt;&#x2F;code&gt; in the cargo binary folder. Later, after building, they will be cached
once again in the same key:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Save Zola cache&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  uses&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; actions&#x2F;cache&#x2F;save@v4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  with&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    path&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &#x2F;usr&#x2F;local&#x2F;cargo&#x2F;registry&#x2F;index&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &#x2F;usr&#x2F;local&#x2F;cargo&#x2F;registry&#x2F;cache&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &#x2F;usr&#x2F;local&#x2F;cargo&#x2F;bin&#x2F;zola&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &#x2F;usr&#x2F;local&#x2F;cargo&#x2F;git&#x2F;db&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;    key&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; zola-${{ env.ZOLA_VERSION }}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  timeout-minutes&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  continue-on-error&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;By default, when retrieving a cache, the action will still succeed if the cache
does not exist. On the other paw, when saving, by default, the action will fail
the entire workflow on failure. This is not a critical component, so we can
allow ourselves to continue if it errors out. In practice, the cache size for
these settings is around 139&amp;amp;thsp;MB on my systems.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Actually_building_Zola_(But_Only_If_Needed)&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Actually_building_Zola_(But_Only_If_Needed)&quot; aria-label=&quot;Anchor link for: Actually_building_Zola_(But_Only_If_Needed)&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Actually building Zola (But Only If Needed)&lt;&#x2F;h2&gt;
&lt;p&gt;Now, here is an excellent trick. i want to know if Zola is already installed,
and only force its install if the version changed (or if it absent for some
reason). The commands that we run in Forgejo actions run on &lt;code&gt;sh&lt;&#x2F;code&gt;, the default
UNIX shell, which means i can use conditions and chains of commands.
Specifically, i want to build Zola only if it does not exist in the &lt;code&gt;$PATH&lt;&#x2F;code&gt; &lt;em&gt;or&lt;&#x2F;em&gt;
if its version is different from the expected one. Formulated otherwise, “either
Zola exists and has the correct version, or i build it”.
That first condition, expressed as a command, looks something like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;which&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; zola&lt;&#x2F;span&gt;&lt;span&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;dev&#x2F;null&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If &lt;code&gt;zola&lt;&#x2F;code&gt; is not in the &lt;code&gt;$PATH&lt;&#x2F;code&gt;, that command will fail. We can chain this with&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;v$(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;zola&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --version&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; cut&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -f 2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;)&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;${{ &lt;&#x2F;span&gt;&lt;span&gt;env&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;ZOLA_VERSION&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; }}&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note the “v” at the start (because Zola formats its version differently in the
command output from how the developers tag releases). Chaining both with &lt;code&gt;&amp;amp;&amp;amp;&lt;&#x2F;code&gt;
means “Zola exists and is the expected version”. If that succeeds, then nothing
happens.&lt;&#x2F;p&gt;
&lt;p&gt;If that fails, we build:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; Install latest zola&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;&quot;&gt;  run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ( which zola &amp;amp;&amp;gt;&#x2F;dev&#x2F;null &amp;amp;&amp;amp; [ &amp;quot;v$(zola --version | cut -d&amp;#39; &amp;#39; -f 2)&amp;quot; = &amp;quot;${{ env.ZOLA_VERSION }}&amp;quot; ] ) || cargo install --force --locked --git https:&#x2F;&#x2F;github.com&#x2F;getzola&#x2F;zola.git --tag ${{ env.ZOLA_VERSION }}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A new option is added, &lt;code&gt;--force&lt;&#x2F;code&gt;, to overwrite the existing binary. Even if the
version changes, &lt;code&gt;cargo&lt;&#x2F;code&gt; will fail to build because it notices that a binary of
the same name already exists in the &lt;code&gt;&#x2F;usr&#x2F;local&#x2F;cargo&#x2F;bin&#x2F;&lt;&#x2F;code&gt; folder.&lt;&#x2F;p&gt;
&lt;p&gt;And &lt;em&gt;voilà&lt;&#x2F;em&gt;. If everything worked correctly, the time taken to actually run the
workflow should be reduced drastically. In my case, Zola will build the first
time any workflow runs, and then the build step will take 0 seconds every time
after. If you modify the key name or list of paths however, the cache will be
invalidated, and you will need to wait for a full rebuild.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;So_What_Did_We_Learn_Exactly&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#So_What_Did_We_Learn_Exactly&quot; aria-label=&quot;Anchor link for: So_What_Did_We_Learn_Exactly&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
So What Did We Learn Exactly&lt;&#x2F;h1&gt;
&lt;p&gt;There are various things i learned throughout this whole ordeal:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Sometimes you can just throw a hack together (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;Lymkwi&#x2F;blog-vulpinecitrus&#x2F;commit&#x2F;5617daf&quot;&gt;&lt;code&gt;5617daf&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, Nov. 2023) and optimize it later (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;Lymkwi&#x2F;blog-vulpinecitrus&#x2F;commit&#x2F;22b14cf&quot;&gt;&lt;code&gt;22b14cf&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, Jul. 2025), when it gets really annoying&lt;&#x2F;li&gt;
&lt;li&gt;Every piece of software is a castle built on sand. If you stray enough from
tested features, if your use case is complex enough, you will pull back at the
walls of user experience like one would pull away the fabric of reality, and
you will unravel the certainty of everything around you.
&lt;span style=&quot;font-size: 98%;&quot;&gt;You will forget the comfort of software that works. &lt;&#x2F;span&gt;
&lt;span style=&quot;font-size: 97%;&quot;&gt;You will lose yourself in those settings, &lt;&#x2F;span&gt;
&lt;span style=&quot;font-size: 96%;&quot;&gt;those crappy hot fixes. The knowledge of some &lt;&#x2F;span&gt;
&lt;span style=&quot;font-size: 92%;&quot;&gt;of the things upon which your infrastructure &lt;&#x2F;span&gt;
&lt;span style=&quot;font-size: 91%;&quot;&gt;hinges will become a part of you, until you, &lt;&#x2F;span&gt;
&lt;span style=&quot;font-size: 90%;&quot;&gt;yourself, become diluted enough that, some day, &lt;&#x2F;span&gt;
&lt;span style=&quot;font-size: 89%;&quot;&gt;you will look in the mirror, and wonder how &lt;&#x2F;span&gt;
&lt;span style=&quot;font-size: 88%;&quot;&gt;much of you is code? How much of you is commands &lt;&#x2F;span&gt;
&lt;span style=&quot;font-size: 87%;&quot;&gt;you memorized? Do machines also feel pain? &lt;&#x2F;span&gt;
&lt;span style=&quot;font-size: 86%;&quot;&gt;Can a hard drive creak the same way your bones &lt;&#x2F;span&gt;
&lt;span style=&quot;font-size: 85%;&quot;&gt;crack when you sit up?&lt;&#x2F;span&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Hosting a git forge is probably worth it, even if you’re the only one using
it. Enabling CI&#x2F;CD on it if it’s only for you is your choice to make, though.
The entire CI&#x2F;CD setup of my forge was carefully setup and debugged
separately over the course of a couple of weeks for another project i host there.
The workflow to deploy this blog piggybacks off of it, but it would not be
worth doing the whole setup of action runners just for that&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-maso-1&quot;&gt;&lt;a href=&quot;#fn-maso&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;li&gt;
&lt;li&gt;The way CI&#x2F;CD works today is almost entirely dictated by how one corporation
did it in their system. GitLab is trying something different, but, in the end,
the GitHub way of doing things seems to be winning out (which can create
friction, like development only considering one platform, as happened with the
artifact actions)&lt;&#x2F;li&gt;
&lt;li&gt;If you have some folks whose entire work it is to do these things all day, buy
them coffee. Seriously.&lt;&#x2F;li&gt;
&lt;li&gt;Software history is fascinating. At a glance, you can probably guess that, to
get to a point where actions work in Forgejo, four different groups who made
software (GitHub, Gogs, Gitea, Forgejo) were involved. Interestingly, there
seems to be an intersection for the last three; and especially the last two.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If you followed along and learned something, let me know. Otherwise, i hope you
now have a good little workflow file to deploy your blog. Have fun!&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-cargoforce&quot;&gt;
&lt;p&gt;Interestingly, as i am writing this blog post, a similar problem
is currently happening on my laptop running Arch Linux, but where
&lt;code&gt;--locked&lt;&#x2F;code&gt; actually makes the build fail because a change in the software
environment is no longer compatible with one of the myriads of dependencies
of Zola. At the moment, removing &lt;code&gt;--locked&lt;&#x2F;code&gt; builds, but having &lt;code&gt;--locked&lt;&#x2F;code&gt;
doesn’t.
✨ s o f t w a r e ✨ &lt;a href=&quot;#fr-cargoforce-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-zolav&quot;&gt;
&lt;p&gt;i cannot guarantee that this exact way of specifying the version will
work if you are trying to build from a specific hash instead. In fact, i can
guarantee that you will at least need to modify the &lt;code&gt;cargo install&lt;&#x2F;code&gt; command to
use &lt;code&gt;--rev&lt;&#x2F;code&gt; instead of &lt;code&gt;--tag&lt;&#x2F;code&gt;. &lt;a href=&quot;#fr-zolav-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-maso&quot;&gt;
&lt;p&gt;or it would be, if your brain is like mine, but it’s a special form
of masochism. &lt;a href=&quot;#fr-maso-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Diving into Radio Listening: Portable Mobile Radio 446</title>
        <published>2025-07-24T00:00:00+00:00</published>
        <updated>2025-07-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/rf-pmr446/"/>
        <id>https://vulpinecitrus.info/blog/rf-pmr446/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/rf-pmr446/">&lt;p&gt;Usage of the radio spectrum is very tightly regulated. Regular, unlicensed
people are allowed only so little of the RF spectrum in emission. In the 90s,
the European Union came together to allocate a small 200 kHz band for
license-free use with the narrow FM mode (FM mode and 12.5 kHz bandwidth). The
name of the norm that would be used on it is Portable Mobile Radio 446, or PMR
446, for short. That little unlicensed band lies within the 70cm ham radio
band.&lt;&#x2F;p&gt;
&lt;p&gt;The original standard actually defined a 1 MHz band (446.0 MHz - 446.1 MHz), with
8 channels. Voice would be modulated by frequency (FM) with a 12.5 kHz bandwidth,
and transmitted on the air at 500mW of power maximum&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-uv5r-1&quot;&gt;&lt;a href=&quot;#fn-uv5r&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. A revision to the
standard would later add another megahertz (446.1 MHz to 446.2 MHz) for a digital
version of the standard using Frequency-Shift Keying for modulation of a digital
voice signal. At some point, both methods of transmitting were allowed to use
the whole 2 MHz band (depending on the country) and we are now left with
walkie-talkies that have 16 channels in Europe.&lt;&#x2F;p&gt;
&lt;p&gt;Oh yeah, because these things are used for walkie-talkies. Baby phones as well.
Camping radios. Construction workers who need cheap radios. Everything the
general public is potentially in a position to use on land for transmitting
over radio in Europe is most likely PMR446. Escape rooms in my city use PMR446.
The cheap radio phone toys kids get for Christmas also use PMR446.&lt;&#x2F;p&gt;
&lt;p&gt;And you can hear all of it. Take any radio, change its mode to narrow (12.5 kHz)
bandwidth, and go to 446.00625 kHz for the first channel, with an increment of
12.5 kHz to get to the next channel.&lt;&#x2F;p&gt;
&lt;p&gt;And.. that’s it. It is very straightforward. i do not have a lot to say about
the technical aspects of listening to these radios, but below are somewhat
disjointed thoughts about listening to PMR446.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;CTCSS_&amp;amp;_DCS_to_Isolate_Communication_Groups&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#CTCSS_&amp;amp;_DCS_to_Isolate_Communication_Groups&quot; aria-label=&quot;Anchor link for: CTCSS_&amp;amp;_DCS_to_Isolate_Communication_Groups&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
CTCSS &amp;amp; DCS to Isolate Communication Groups&lt;&#x2F;h1&gt;
&lt;p&gt;With only 16 channels available, there is a possibility that you could
interfere with someone else who is also using that channel. If you both emit
sparsely, you could use a mechanism to know which emission is meant for who, and
only enable reception when you’re signaled to do so.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;em&gt;Continuous Tone-Coded Squelch System&lt;&#x2F;em&gt; is a signaling technique where an
emitting radio will add a very low constant tone to the voice being
transmitted. There is a list of different tones that define different subgroups
within a common channel: receiving equipment that is configured for a specific
CTCSS code will only consider that a received signal is meant to be listened to
when the de-modulated audio contains the correct CTCSS frequency. CTCSS does
ont guarantee any real privacy however: you can bypass this mechanism by not
setting any CTCSS code at reception, or using bypass features (such as
“Monitor” buttons on some radios, or an SDR which does not care about CTCSS at
all), will let you receive all voices transmitted regardless of whether the
CTCSS code is the correct one.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Digital-Coded Squelch&lt;&#x2F;em&gt; (DCS), also called &lt;em&gt;Continuous Digital-Coded Squelch
System&lt;&#x2F;em&gt; (CDCSS), is the digital little brother of CTCSS. In DCS, an inaudible
stream is added to the transmitted audio containing a code and some
error-correction, which eventually decode to 9 bits that are used to encode a
number. Complicated error-correction maths detailed on the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Digital-Coded_Squelch#DCS&quot;&gt;wikipedia
page&lt;&#x2F;a&gt; explains that
out of those 512 possible combinations, 83 are kept to avoid false positives
due to alignment problems.&lt;&#x2F;p&gt;
&lt;p&gt;CTCSS and DCS are not exclusive to PMR446, but they are often incorporated as
built-in features in consumer-grade radios.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;My_Own_Portable_Mobile_Raspberry_446&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#My_Own_Portable_Mobile_Raspberry_446&quot; aria-label=&quot;Anchor link for: My_Own_Portable_Mobile_Raspberry_446&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
My Own Portable Mobile Raspberry 446&lt;&#x2F;h1&gt;
&lt;p&gt;i had an old raspberry pi lying around, which used to be my old router before
the current one. While &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.buzzfeednews.com&#x2F;article&#x2F;chrisstokelwalker&#x2F;raspberry-pi-hired-ex-cop-mastodon-controversy&quot;&gt;i would not buy one of those anymore today&lt;&#x2F;a&gt;, i
still have a couple boards that have no use. i installed a clean Debian for
Raspberry Pi on it and designed a little system that goes as follows:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The Raspberry Pi boots when plugged on an external battery inside my bag. That
battery is big enough to charge up my phone twice and still have some juice
left;&lt;&#x2F;li&gt;
&lt;li&gt;My phone is plugged into one of the USB ports of the board and provides
internet access via USB tethering;&lt;&#x2F;li&gt;
&lt;li&gt;the RTL-SDR dongle is plugged on another port of the board, and a little 33&amp;amp;nbps;cm
antenna is neatly attached to the outside of my bag;&lt;&#x2F;li&gt;
&lt;li&gt;The raspberry pi launches two important pieces of software at boot: a
Wireguard interface that connects to a remote Wireguard server, and WebSDR,
which binds to the Wireguard interface;&lt;&#x2F;li&gt;
&lt;li&gt;My phone shares the same Wireguard network and is also connected to my
Wireguard server, and i use it to access WebSDR with a profile set up for
PMR446.&lt;&#x2F;li&gt;
&lt;li&gt;Alternatively, i turn off WebSDR and use the shared network to SSH onto the
board from my phone and launch a scanning command for PMR446, while my
headphones are plugged on the phone jack;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;And then, just walk around. It is not by any means discrete: you have an antenna
that sticks out, but otherwise you should be pretty innocuous. Most people will
think you are a weirdo.&lt;&#x2F;p&gt;
&lt;p&gt;The exact scanning command for a RTL-SDR should be something along the lines of:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rtl_fm -s 22050 -l 10 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-f 466006250 -f 446018750 -f 446031250 -f 446043750 -f 446056250 -f 446068750 -f 446081250 -f 446093750 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-f 466106250 -f 446118750 -f 446131250 -f 446143750 -f 446156250 -f 446168750 -f 446181250 -f 446193750&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Which will rapidly scan all the frequencies (&lt;code&gt;-f&lt;&#x2F;code&gt;) and lock on to one as long as
it passes the squelch level (&lt;code&gt;-l&lt;&#x2F;code&gt;). Fidget a bit with the level depending on how
much noise you get, and remove frequencies that are polluted by noise as well.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;The_Voyeur_&amp;amp;_The_Watcher&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#The_Voyeur_&amp;amp;_The_Watcher&quot; aria-label=&quot;Anchor link for: The_Voyeur_&amp;amp;_The_Watcher&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
The Voyeur &amp;amp; The Watcher&lt;&#x2F;h1&gt;
&lt;p&gt;This gets into a more philosophical argument about privacy. To an extent, it
should be common knowledge that whenever you emit on the air, anybody with a
receiver will potentially pick your signal up and, unless you are a cop or the
military, you are not allowed to encrypt it. On the other paw, i was also a kid
with a walkie-talkie playing with friends, and it makes me queasy to know that
sometimes, the voices i pick up when scanning the 16 channels of PMR446 are
children. This
whole dynamic is true of most frequencies in fact. As a listener, you are in a
position where you observe signals that are most often explicitly put over the
radio by people who intend for &lt;em&gt;anyone who can&lt;&#x2F;em&gt; to pick them up. Amateur radio bands
are made to be listened to by hams and non-hams. Commercial FM radio is expected
to be listened to by a wide audience, and so is AM radio in countries that still
emit it (or via Skywave, a topic for a later article). Pager protocols (another
topic for an upcoming article) are also transmitted and repeated over the air,
but, from my experience, some people who use that are not as worried as they
(perhaps) should about who can see what goes on it. Listening to the airwaves
might be a form of weird expensive voyeurism, but, to an extent, a lot of people
who voluntarily &lt;em&gt;emit&lt;&#x2F;em&gt; on the airwaves are themselves exhibitionists.&lt;&#x2F;p&gt;
&lt;p&gt;PMR446 was, when i wrote the first draft of this article, one of the most
common bands i scan, because whenever you go to any densely populated area or
facility where people will need to communicate over short-to-medium distances
simply, there will be walkie-talkies. Private security, airports train
stations, you get it. There’s a weird feeling in &lt;em&gt;knowing&lt;&#x2F;em&gt; what is happening
around you in the backrooms, though the law compels you &lt;em&gt;not&lt;&#x2F;em&gt; to act upon it
(as you are not the intended recipient). Sometimes, i stay on the same channel
and listen to two guys talking for half an hour about everything or nothing.
Often, though, when i clearly feel that the people involved have no idea anyone
can listen to them, i just.. go listen to somewhere else.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Conclusion&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Conclusion&quot; aria-label=&quot;Anchor link for: Conclusion&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Conclusion&lt;&#x2F;h1&gt;
&lt;p&gt;PMR446 is not the end-all-be-all of portable mobile radios. In fact, in an
upcoming post, i will discuss another PMR protocol, fully digital this time,
that was standardized in Europe: &lt;strong&gt;Te&lt;&#x2F;strong&gt;rrestrial &lt;strong&gt;T&lt;&#x2F;strong&gt;runked &lt;strong&gt;Ra&lt;&#x2F;strong&gt;dio (TETRA).&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-uv5r&quot;&gt;
&lt;p&gt;Now is the moment i say that despite owning a Baofeng UV-5R, for legal
reasons, i have never once pressed the Tx button and transmitted on PMR446
at 1W, twice the maximum legal limit for Effective Radiated Power (ERP), nor
should you. You should definitely not transmit at twice the maximum ERP, nor
own a radio banned in multiple countries for polluting the harmonics of your
carrier frequency. :3 &lt;a href=&quot;#fr-uv5r-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Enabling bias-tee on RTL-SDR dongles through GnuRadio&#x27;s OsmoSDR Source</title>
        <published>2025-02-28T00:00:00+00:00</published>
        <updated>2025-02-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/gnuradio-rtlsdr-osmosdr-biast/"/>
        <id>https://vulpinecitrus.info/blog/gnuradio-rtlsdr-osmosdr-biast/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/gnuradio-rtlsdr-osmosdr-biast/">&lt;details&gt;
&lt;summary&gt;&lt;b&gt;Too Long, Won&#x27;t Read&lt;&#x2F;b&gt;&lt;&#x2F;summary&gt;
&lt;p&gt;Add &lt;code&gt;rtl,bias=1&lt;&#x2F;code&gt; in the device arguments. Both options are needed.&lt;&#x2F;p&gt;
&lt;&#x2F;details&gt;
&lt;br&gt;
&lt;p&gt;i like my &lt;em&gt;Low-Noise Amplifier&lt;&#x2F;em&gt;. It helps my dingy little antenna and RTL-SDR
dongle pick up signals that otherwise would be very much out of reach. That
little amplifier is plugged on the transmission line as close as possible to the
antenna, and powered through &lt;em&gt;bias-tee&lt;&#x2F;em&gt;. A
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Bias_tee&quot;&gt;bias-tee&lt;&#x2F;a&gt; (or bias-t) is a little
circuit designed to add a constant DC voltage to an alternating one, such as
radio-frequency signals. Here, it lets me send power from the USB port my dongle
is plugged in, through the dongle and along the transmission line all the way to
the amplifier, which is then powered by that DC voltage (in my case 5V DC) .&lt;&#x2F;p&gt;
&lt;p&gt;For most situations where i used my &lt;abbr title=&quot;Software-Defined
Radio&quot;&gt;SDR&lt;&#x2F;abbr&gt;
 so far, i could use the &lt;code&gt;rtl_biast&lt;&#x2F;code&gt; command line tool to enable
bias-tee prior to running the utility i needed. Other times, there was a
dedicated option for enabling it.&lt;&#x2F;p&gt;
&lt;p&gt;Then, i played with receiving GSM data using Piotr Krysik’s
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ptrkrysik&#x2F;gr-gsm&quot;&gt;&lt;code&gt;gr-gsm&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-gsm-1&quot;&gt;&lt;a href=&quot;#fn-gsm&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. Recently, i &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;lymkwi&#x2F;gr-gsm&#x2F;&quot;&gt;forked
it&lt;&#x2F;a&gt; to fix build issues on newer
versions of Boost. &lt;code&gt;gr-gsm&lt;&#x2F;code&gt;’s scripts use &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.gnuradio.org&#x2F;&quot;&gt;GNURadio&lt;&#x2F;a&gt;,
a flow-based system for building digital signal processing pipelines from basic
building blocks. Scripting it helps provide a clean front-end for users to just,
for example, receive GSM traffic from a nearby antenna, or split a single
recording into multiple capture files depending on the antenna frequency, all
without having to open the GNURadio companion software to tweak a massive
diagram of thousands of blocks.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;gr-gsm&lt;&#x2F;code&gt; is supposed to work with basically any radio source that is supported
by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;osmocom.org&#x2F;projects&#x2F;gr-osmosdr&#x2F;wiki&quot;&gt;OsmoSDR&lt;&#x2F;a&gt;, a SDR software
abstraction layer developed by the OsmoCom group. In order to provide
device-specific arguments, however, we need to fill a free-form text field in
the OsmoSDR Source block. &lt;code&gt;gr-gsm&lt;&#x2F;code&gt; gives you the option to do so, but does not
document anywhere what options are available for what dongles.&lt;&#x2F;p&gt;
&lt;p&gt;After stumbling upon a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;RTLSDR&#x2F;comments&#x2F;kyrne6&#x2F;rtlsdrcom_v3_bias_tee_and_gnu_radio&#x2F;&quot;&gt;reddit
post&lt;&#x2F;a&gt;,
i opened the documentation of
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gnss-sdr.org&#x2F;docs&#x2F;sp-blocks&#x2F;signal-source&#x2F;#implementation-osmosdr_signal_source&quot;&gt;&lt;code&gt;gnss-sdr&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
of all places&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-gnss-1&quot;&gt;&lt;a href=&quot;#fn-gnss&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. In that specific page lies a table with some information
on how to enable bias-tee for HackRF One, bladeRF and RTL-SDR Blog V3 dongles. i
own a V4 dongle, but the option hasn’t changed:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SignalSource.osmosdr_args=rtl,bias=1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So, back to &lt;code&gt;gr-gsm&lt;&#x2F;code&gt;, i just input:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;grgsm_livemon -f 921.8M -g 30.0 --serverport 4730 --args=&amp;quot;rtl,bias=1&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That last bit, &lt;code&gt;rtl,bias=1&lt;&#x2F;code&gt;, is the part you need to provide as device
arguments. Both &lt;code&gt;rtl&lt;&#x2F;code&gt; and &lt;code&gt;bias=1&lt;&#x2F;code&gt; need to be present for a RTL-SDR dongle’s
bias-tee to turn on.&lt;&#x2F;p&gt;
&lt;!--
vim: set cc=80 tw=80 spell:
--&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-gsm&quot;&gt;
&lt;p&gt;i will definitely discuss GSM in a later article, don’t worry. &lt;a href=&quot;#fr-gsm-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-gnss&quot;&gt;
&lt;p&gt;and i will also talk about GNSS at some point, but first i need to make
&lt;code&gt;gnss-sdr&lt;&#x2F;code&gt; work with Galileo first. &lt;a href=&quot;#fr-gnss-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>What if any process could handle SIGKILL?</title>
        <published>2025-02-14T00:00:00+00:00</published>
        <updated>2025-02-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/what-if-you-could-handle-sigkill/"/>
        <id>https://vulpinecitrus.info/blog/what-if-you-could-handle-sigkill/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/what-if-you-could-handle-sigkill/">&lt;p&gt;i was recently having a discussion online about different perspectives on
signals. It led to a question me and someone else asked simultaneously: what if
you could &lt;em&gt;ignore&lt;&#x2F;em&gt; or &lt;em&gt;handle&lt;&#x2F;em&gt; the absolute, unstoppable order from the kernel
to be killed or stopped?&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Signals&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Signals&quot; aria-label=&quot;Anchor link for: Signals&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Signals&lt;&#x2F;h1&gt;
&lt;p&gt;Signals in POSIX are a form of &lt;abbr title=&quot;Inter-Process Communication&quot;&gt;IPC&lt;&#x2F;abbr&gt;
 that allows
userland processes (and the kernel) to send each other simple indications of
actions to take. The Linux kernel, at the time of writing, handles about &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;arch&#x2F;x86&#x2F;include&#x2F;uapi&#x2F;asm&#x2F;signal.h#L22&quot;&gt;31 of
those&lt;&#x2F;a&gt;
on the x86(-64) architecture. The most frequent situation where you might
encounter signals as a developer is when making &lt;em&gt;handlers&lt;&#x2F;em&gt; for these signals:
callbacks which are to be executed upon the reception of a signal by your
process. You may also &lt;em&gt;mask&lt;&#x2F;em&gt; these signals to stop them from triggering anything
on your program.&lt;&#x2F;p&gt;
&lt;p&gt;There are, however, two signals that cannot be stopped or handled: &lt;code&gt;SIGKILL&lt;&#x2F;code&gt; and
&lt;code&gt;SIGSTOP&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;SIGKILL&lt;&#x2F;code&gt; is an indication to terminate immediately and messily. Essentially,
the process receiving this signal is abruptly ended, and marked as dead. Its
parent must then, at some point, reap it so that resources can be freed.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;SIGSTOP&lt;&#x2F;code&gt; is a weirder signal. When a process is running on a CPU and receives
&lt;code&gt;SIGSTOP&lt;&#x2F;code&gt;, it is marked as blocked and removed from the running CPU (or moved in
the background from the point of view of the user). After getting stopped, a
process remains stuck until receiving a &lt;code&gt;SIGCONT&lt;&#x2F;code&gt; signal. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;include&#x2F;linux&#x2F;signal.h#L422&quot;&gt;Multiple
signals&lt;&#x2F;a&gt;
can indicate a block, but &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt; is the only unavoidable one of those. You
may know that you can stop a process in a shell, via &lt;code&gt;^Z&lt;&#x2F;code&gt;. Shells usually do not
throw &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt; directly, but &lt;code&gt;SIGTSTP&lt;&#x2F;code&gt;, which may be caught or fail. &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt;
is considered “reserved” for the kernel only to throw.&lt;&#x2F;p&gt;
&lt;p&gt;So, what if we &lt;em&gt;could&lt;&#x2F;em&gt; ignore, or even handle &lt;code&gt;SIGKILL&lt;&#x2F;code&gt; and &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt;? Surely,
because everyone in userspace made sure to &lt;em&gt;never&lt;&#x2F;em&gt; register a handler on those
signals or ignore them, things shouldn’t go wrong, right?&lt;&#x2F;p&gt;
&lt;p&gt;…right?&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Fucking_Around:_Messing_with_Linux&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Fucking_Around:_Messing_with_Linux&quot; aria-label=&quot;Anchor link for: Fucking_Around:_Messing_with_Linux&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Fucking Around: Messing with Linux&lt;&#x2F;h1&gt;
&lt;p&gt;My initial idea was to go into the signal handling code of Linux and remove
anything that treats &lt;code&gt;SIGKILL&lt;&#x2F;code&gt; or &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt; differently from other signals. i
had originally wondered what exactly makes these two signals specials. It did
not take long to realize that Linux’s signal handling code explicitly treats
them very differently.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;How_Linux_Handles_Firing_Signals&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#How_Linux_Handles_Firing_Signals&quot; aria-label=&quot;Anchor link for: How_Linux_Handles_Firing_Signals&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
How Linux Handles Firing Signals&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s go through a simple overview of how signals firing are handled by the
Linux kernel. For the sake of clarity, have a little diagram, so you can follow
along:&lt;&#x2F;p&gt;
&lt;img src=&quot;signals.drawio.png&quot; style=&quot;margin-left: auto; margin-right: auto; display: block;&quot; &#x2F;&gt;
&lt;p&gt;Linux’s implementation of signals explicitly refuses that user processes mask
&lt;code&gt;SIGKILL&lt;&#x2F;code&gt; and &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt; or handle them. About all of that logic is located in
&lt;code&gt;kernel&#x2F;signal.c&lt;&#x2F;code&gt; and in the appropriate &lt;code&gt;arch&#x2F;$ARCH&#x2F;kernel&#x2F;signal(_?(32|64)?.c&lt;&#x2F;code&gt;
file. i will give examples in &lt;code&gt;arch&#x2F;x86&#x2F;kernel&#x2F;signal.c&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;When the kernel is about to leave kernelspace, in &lt;code&gt;kernel&#x2F;entry&#x2F;common.c&lt;&#x2F;code&gt;’s
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;entry&#x2F;common.c#L90&quot;&gt;&lt;code&gt;exit_to_user_mode_loop&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;,
it checks for work left over to handle. That includes &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;entry&#x2F;common.c#L111&quot;&gt;pending
signals&lt;&#x2F;a&gt;
to be sent or handled. When some signals are pending, Linux will next run
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;arch&#x2F;x86&#x2F;kernel&#x2F;signal.c#L333&quot;&gt;&lt;code&gt;arch_do_signal_or_restart&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
for the current architecture. There are essentially three steps in that
function: &lt;em&gt;getting&lt;&#x2F;em&gt; the signal and &lt;em&gt;handling&lt;&#x2F;em&gt; the signal if a user-defined
handler was found.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L2801&quot;&gt;&lt;code&gt;get_signal&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
runs a loop to dequeue signals that are not masked and process them. Right after
dequeuing, the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L2928&quot;&gt;potential
handler&lt;&#x2F;a&gt; is
retrieved. And, if that handler is not the default handler that ignores the
signal (&lt;code&gt;SIG_IGN&lt;&#x2F;code&gt;), it is stored in a &lt;code&gt;ksignal&lt;&#x2F;code&gt; structure and &lt;code&gt;get_signal&lt;&#x2F;code&gt;
returns. Otherwise, the code checks for, among other things, whether the target
process is a global init and the signal can be ignored, and whether the signal
is a kind of &lt;code&gt;stop&lt;&#x2F;code&gt;. If that latter case is true, we prepare the process to be
stopped and call &lt;code&gt;do_signal_stop&lt;&#x2F;code&gt;, which handles &lt;em&gt;all&lt;&#x2F;em&gt; stop signals. Finally, if
the signal is not a kind of stop and was not handled, its default behaviour is
killing the process, which is done via &lt;code&gt;do_group_exit&lt;&#x2F;code&gt;. While scouring Linux’s
code initially, his gave me a first intuition: the kernel &lt;em&gt;expects&lt;&#x2F;em&gt; that there
is no user-set handler for &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt; and &lt;code&gt;SIGKILL&lt;&#x2F;code&gt; in order to fall back on
default behaviour. If there was a user-set handler, they would be handled like
regular signals. Either there is logic right at the entry of handler setup code
that explicitly removes &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt; and &lt;code&gt;SIGKILL&lt;&#x2F;code&gt;, or that check is &lt;em&gt;outside of
Linux&lt;&#x2F;em&gt;, which could mean having to rewrite parts of libc, or using raw syscalls.&lt;&#x2F;p&gt;
&lt;p&gt;If the signal is not handled by the kernel in &lt;code&gt;get_signal&lt;&#x2F;code&gt;, i.e. a handler is
set in &lt;code&gt;ksig&lt;&#x2F;code&gt;, the kernel then calls &lt;code&gt;handle_signal&lt;&#x2F;code&gt;. Just as with many other
functions in Linux, the name is deceptive: no signal is actually handled in
there (in fact, as far as i have seen, it is the only part of the top-level
signal handling function &lt;code&gt;arch_do_signal_or_restart&lt;&#x2F;code&gt; that never handles
signals). What &lt;code&gt;handle_signal&lt;&#x2F;code&gt; does is that it sets up the stack frame of the
signal handler and sets and saves pointers to restart execution in user mode
later. The process goes through &lt;code&gt;handle_signal&lt;&#x2F;code&gt; as defined in your &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;arch&#x2F;x86&#x2F;kernel&#x2F;signal.c#L255&quot;&gt;current
architecture&lt;&#x2F;a&gt;,
which, on x86(-64), then calls
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;arch&#x2F;x86&#x2F;kernel&#x2F;signal.c#L236&quot;&gt;&lt;code&gt;setup_rt_frame&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
to set up a return frame with the correct &lt;abbr title=&quot;Application
Binary Interface&quot;&gt;ABI&lt;&#x2F;abbr&gt;
 for the signal. On x86, the state of the &lt;abbr title=&quot;Floating Point Unit&quot;&gt;FPU&lt;&#x2F;abbr&gt;
 is also saved and reset. Down
at the last function in the call chain for frame setup, the instruction pointer
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;arch&#x2F;x86&#x2F;kernel&#x2F;signal_64.c#L210&quot;&gt;is
set&lt;&#x2F;a&gt;
to &lt;code&gt;ksig-&amp;gt;ka.sa.sa_handler&lt;&#x2F;code&gt;, so that when those registers are restored the
machine immediately executes your handler. After all of that is done,
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L3079&quot;&gt;&lt;code&gt;signal_setup_done&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
is called to change some internal states, and the frame setup is done.&lt;&#x2F;p&gt;
&lt;p&gt;At the end of an iteration of the work loop in &lt;code&gt;exit_to_user_mode_loop&lt;&#x2F;code&gt;, the
kernel &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;entry&#x2F;common.c#L117&quot;&gt;returns to user
mode&lt;&#x2F;a&gt;
to execute the necessary work.&lt;&#x2F;p&gt;
&lt;p&gt;Userspace programs use the
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L4606&quot;&gt;&lt;code&gt;rt_sigaction&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
syscall as the entry point to set a handler for a signal. This one does not
specifically exclude our signals until you look at
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L4285&quot;&gt;&lt;code&gt;do_sigaction&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;,
which checks for something called
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;include&#x2F;linux&#x2F;signal.h#L445&quot;&gt;&lt;code&gt;sig_kernel_only&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.
That macro checks if the signal is one of &lt;code&gt;SIGKILL&lt;&#x2F;code&gt; or &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt; and throws out
a &lt;code&gt;-EINVAL&lt;&#x2F;code&gt; if that is true. This means that, as expected, there was logic
somewhere early when the kernel receives a handler setup syscall that explicitly
prevents setting one for &lt;code&gt;SIGKILL&lt;&#x2F;code&gt; or &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Linux_and_Masked_Signals&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Linux_and_Masked_Signals&quot; aria-label=&quot;Anchor link for: Linux_and_Masked_Signals&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Linux and Masked Signals&lt;&#x2F;h2&gt;
&lt;p&gt;As for setting &lt;em&gt;masks&lt;&#x2F;em&gt;, the set of signals ignored for a given task, the kernel
entry point is
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L3320&quot;&gt;&lt;code&gt;rt_sigprocmask&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.
It &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L3335&quot;&gt;explicitly
prevents&lt;&#x2F;a&gt;
blocking either &lt;code&gt;SIGKILL&lt;&#x2F;code&gt; or &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt; before calling
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L3237&quot;&gt;&lt;code&gt;sigprocmask&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.
When a signal is sent, before queuing,
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L870&quot;&gt;&lt;code&gt;prepare_signal&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
is called. One of its roles is checking that a signal is blocked or cannot be
delivered (global init is the target, the target is unkillable in some way,
etc). Surprisingly, &lt;em&gt;blocked signals are always queued&lt;&#x2F;em&gt;, because the signal mask
and handling might change between queueing and dequeueing. However, if the
signal is not masked but &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L80&quot;&gt;no handler is
set&lt;&#x2F;a&gt;, it will
get
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L1053&quot;&gt;dropped&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;From reading the code that handles signals, signal masking and signal handlers,
it’s clear that there are multiple places that explicitly exclude setting
handlers for and masking &lt;code&gt;SIGKILL&lt;&#x2F;code&gt; and &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;So i went in and patched them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Patching_Linux&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Patching_Linux&quot; aria-label=&quot;Anchor link for: Patching_Linux&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Patching Linux&lt;&#x2F;h2&gt;
&lt;p&gt;There are four things i need to look at:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Allowing processes to mask (&lt;code&gt;sigprocmask&lt;&#x2F;code&gt;) both kernel signals&lt;&#x2F;li&gt;
&lt;li&gt;Allowing processes to handle (&lt;code&gt;sigaction&lt;&#x2F;code&gt;) both kernel signals&lt;&#x2F;li&gt;
&lt;li&gt;Making sure that if a handler is set for one of these two signals, or they are
masked, that the default behaviour is masked&lt;&#x2F;li&gt;
&lt;li&gt;Patching any other instance of &lt;code&gt;SIGKILL&lt;&#x2F;code&gt; or &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt; explicitly mentioned in
&lt;code&gt;kernel&#x2F;signal.c&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;i begin with creating a simple KConfig key in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;lib&#x2F;Kconfig.debug#L2&quot;&gt;“Kernel
Hacking”&lt;&#x2F;a&gt;
menu in &lt;code&gt;lib&#x2F;Kconfig.debug&lt;&#x2F;code&gt;. This is the first part of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;Lymkwi&#x2F;linux&#x2F;commit&#x2F;3bc478b0ac9afd6274e9f90a8a024e759da1b3e4.patch&quot;&gt;my patch&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;config KILL_STOP_HANDLING&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	bool &amp;quot;Make SIGSTOP and SIGKILL handlable by regular programs&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	help&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	  This prevents the kernel from blocking handling of SIGSTOP and SIGKILL by&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	  regular user programs.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	  If unsure, say N.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Starting from there, i can hide or replace any part of signal handling code that
explicitly refuses &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt; or &lt;code&gt;SIGKILL&lt;&#x2F;code&gt; using something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#ifdef&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; CONFIG_KILL_STOP_HANDLING&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; Code that does not discriminate signals&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; Previous code&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#endif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So, let’s get started.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Signal_Masking_Syscall&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Signal_Masking_Syscall&quot; aria-label=&quot;Anchor link for: Signal_Masking_Syscall&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
Signal Masking Syscall&lt;&#x2F;h3&gt;
&lt;p&gt;Your machine enters the signal masking procedure via the
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L3320&quot;&gt;&lt;code&gt;rt_sigprocmask&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
syscall (previously &lt;code&gt;sigprocmask&lt;&#x2F;code&gt; before real-time signals were introduced):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; *  sys_rt_sigprocmask - change the list of currently blocked signals&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; *  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;@how:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; whether to add, remove, or set signals&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; *  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;@nset:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; stores pending signals&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; *  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;@oset:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; previous value of signal mask if non-null&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; *  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;@sigsetsize:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; size of sigset_t type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;SYSCALL_DEFINE4&lt;&#x2F;span&gt;&lt;span&gt;(rt_sigprocmask,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; int&lt;&#x2F;span&gt;&lt;span&gt;, how,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; sigset_t&lt;&#x2F;span&gt;&lt;span&gt; __user &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;, nset,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;		sigset_t&lt;&#x2F;span&gt;&lt;span&gt; __user &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;, oset,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; size_t&lt;&#x2F;span&gt;&lt;span&gt;, sigsetsize)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In that function, after some declarations and tests, if the &lt;code&gt;nset&lt;&#x2F;code&gt; argument is
&lt;code&gt;true&lt;&#x2F;code&gt;, we proceed to call &lt;code&gt;sigprocmask&lt;&#x2F;code&gt; after copying the &lt;code&gt;new_set&lt;&#x2F;code&gt; of signals:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;copy_from_user&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;new_set&lt;&#x2F;span&gt;&lt;span&gt;, nset,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; sizeof&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;sigset_t&lt;&#x2F;span&gt;&lt;span&gt;)))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    return -&lt;&#x2F;span&gt;&lt;span&gt;EFAULT;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sigdelsetmask&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;new_set&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sigmask&lt;&#x2F;span&gt;&lt;span&gt;(SIGKILL)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sigmask&lt;&#x2F;span&gt;&lt;span&gt;(SIGSTOP));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;error &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sigprocmask&lt;&#x2F;span&gt;&lt;span&gt;(how,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;new_set&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; NULL&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; (error)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span&gt; error;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you don’t blink, you can actually catch an explicit reference to our kernel
signals! Right before moving to the actual handler of the syscall’s operation,
we see a call to &lt;code&gt;sigdelsetmask&lt;&#x2F;code&gt;, which is more or less a “remove from set”
operation“ (a &lt;em&gt;set negation&lt;&#x2F;em&gt; and &lt;em&gt;store&lt;&#x2F;em&gt;). It is actually implemented as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;include&#x2F;linux&#x2F;signal.h#L227&quot;&gt;&lt;code&gt;sig &amp;amp;= ~mask&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This little line can be easily masked:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#ifndef CONFIG_KILL_STOP_HANDLING&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    sigdelsetmask(&amp;amp;new_set, sigmask(SIGKILL)|sigmask(SIGSTOP));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#endif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;sigprocmask&lt;&#x2F;code&gt; can actually perform different operations depending on &lt;code&gt;how&lt;&#x2F;code&gt;,
which can be any of &lt;code&gt;SIG_BLOCK&lt;&#x2F;code&gt;, &lt;code&gt;SIG_UNBLOCK&lt;&#x2F;code&gt;, and &lt;code&gt;SIG_SETMASK&lt;&#x2F;code&gt;. The first two
are operations over the existing mask, whereas the last one sets the mask from
exactly what you give.&lt;&#x2F;p&gt;
&lt;p&gt;The code of that function, in
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L3237&quot;&gt;&lt;code&gt;kernel&#x2F;signal.c&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
(again) then does the following. It sets &lt;code&gt;oldset&lt;&#x2F;code&gt; to the old set, and then
dispatches over the value of &lt;code&gt;how&lt;&#x2F;code&gt; to perform the correct binary operation
between the &lt;code&gt;oldset&lt;&#x2F;code&gt; and the &lt;code&gt;set&lt;&#x2F;code&gt; it is given:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sigprocmask&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; how&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; sigset_t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;set&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; sigset_t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;oldset&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;	struct&lt;&#x2F;span&gt;&lt;span&gt; task_struct &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;tsk &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; current;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;	sigset_t&lt;&#x2F;span&gt;&lt;span&gt; newset;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;	&#x2F;* Lockless, only current can change -&amp;gt;blocked, never from irq *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;	if&lt;&#x2F;span&gt;&lt;span&gt; (oldset)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;		*&lt;&#x2F;span&gt;&lt;span&gt;oldset &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; tsk-&amp;gt;blocked;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;	switch&lt;&#x2F;span&gt;&lt;span&gt; (how) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;	case&lt;&#x2F;span&gt;&lt;span&gt; SIG_BLOCK:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;		sigorsets&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;newset&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;tsk&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;blocked&lt;&#x2F;span&gt;&lt;span&gt;, set);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;		break&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;	case&lt;&#x2F;span&gt;&lt;span&gt; SIG_UNBLOCK:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;		sigandnsets&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;newset&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;tsk&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;blocked&lt;&#x2F;span&gt;&lt;span&gt;, set);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;		break&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;	case&lt;&#x2F;span&gt;&lt;span&gt; SIG_SETMASK:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		newset &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;= *&lt;&#x2F;span&gt;&lt;span&gt;set;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;		break&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;	default&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;		return -&lt;&#x2F;span&gt;&lt;span&gt;EINVAL;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;	&#x2F;&#x2F; ... SNIP ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As the comment points out, this function will “happy block “unblockable”
signals like SIGKILL and friends“. As such, there’s no need to keep going in the
chain of calls. In fact, the rest of the calls only deal with taking locks,
setting sets, and such.&lt;&#x2F;p&gt;
&lt;p&gt;There are other places where &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt; and &lt;code&gt;SIGKILL&lt;&#x2F;code&gt; are mentioned for masking:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L3207&quot;&gt;&lt;code&gt;set_current_blocked&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; is meant to be a user-mode friendly entrypoint to block a given set of signals. It removes &lt;code&gt;SIGKILL&lt;&#x2F;code&gt; and &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt; preventively, so we can remove that.&lt;&#x2F;li&gt;
&lt;li&gt;the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L3351&quot;&gt;compatibility definition of &lt;code&gt;rt_sigprocmask&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; also explicitly blocks our two signals, exactly the same way &lt;code&gt;rt_sigprocmask&lt;&#x2F;code&gt; does&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;Signal_Handler_Setup_Syscall&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Signal_Handler_Setup_Syscall&quot; aria-label=&quot;Anchor link for: Signal_Handler_Setup_Syscall&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
Signal Handler Setup Syscall&lt;&#x2F;h3&gt;
&lt;p&gt;Similarly to before, the syscall for entry is
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L4606&quot;&gt;&lt;code&gt;rt_sigaction&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; *  sys_rt_sigaction - alter an action taken by a process&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; *  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;@sig:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; signal to be sent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; *  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;@act:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; new sigaction&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; *  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;@oact:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; used to save the previous sigaction&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; *  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;@sigsetsize:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; size of sigset_t type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;SYSCALL_DEFINE4&lt;&#x2F;span&gt;&lt;span&gt;(rt_sigaction,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; int&lt;&#x2F;span&gt;&lt;span&gt;, sig,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;		const struct&lt;&#x2F;span&gt;&lt;span&gt; sigaction __user &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;, act,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;		struct&lt;&#x2F;span&gt;&lt;span&gt; sigaction __user &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;, oact,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;		size_t&lt;&#x2F;span&gt;&lt;span&gt;, sigsetsize)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Nothing in the code explicitly talks about &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt; or &lt;code&gt;SIGKILL&lt;&#x2F;code&gt;, so let us
inspect the next step:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ret &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; do_sigaction&lt;&#x2F;span&gt;&lt;span&gt;(sig, act &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;? &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;new_sa &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; NULL&lt;&#x2F;span&gt;&lt;span&gt;, oact &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;? &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;old_sa &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; NULL&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L4279&quot;&gt;&lt;code&gt;do_sigaction&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;,
the code goes as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; do_sigaction&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; sig&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span&gt; k_sigaction &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;act&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span&gt; k_sigaction &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;oact&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;	struct&lt;&#x2F;span&gt;&lt;span&gt; task_struct &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;p &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; current,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span&gt;t;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;	struct&lt;&#x2F;span&gt;&lt;span&gt; k_sigaction &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;k;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;	sigset_t&lt;&#x2F;span&gt;&lt;span&gt; mask;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;	if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;valid_signal&lt;&#x2F;span&gt;&lt;span&gt;(sig)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;&#x2F;span&gt;&lt;span&gt; sig &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ||&lt;&#x2F;span&gt;&lt;span&gt; (act &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sig_kernel_only&lt;&#x2F;span&gt;&lt;span&gt;(sig)))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;		return -&lt;&#x2F;span&gt;&lt;span&gt;EINVAL;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	k &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;= &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;p-&amp;gt;sighand-&amp;gt;action[sig&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;	spin_lock_irq&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;p-&amp;gt;sighand-&amp;gt;siglock);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;	if&lt;&#x2F;span&gt;&lt;span&gt; (k-&amp;gt;sa.sa_flags&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt; SA_IMMUTABLE) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;		spin_unlock_irq&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;p-&amp;gt;sighand-&amp;gt;siglock);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;		return -&lt;&#x2F;span&gt;&lt;span&gt;EINVAL;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There is a check that the signal number is not valid (too big), or inferior to 1
(also invalid), or that there is a new &lt;code&gt;k_sigaction&lt;&#x2F;code&gt; to setup &lt;em&gt;and&lt;&#x2F;em&gt; the signal
is &lt;em&gt;kernel only&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Kernel only, huh?&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;include&#x2F;linux&#x2F;signal.h#L445&quot;&gt;&lt;code&gt;sig_kernel_only&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
is defined as a call to &lt;code&gt;siginmask&lt;&#x2F;code&gt;, with the set of signals
&lt;code&gt;SIG_KERNEL_ONLY_MASK&lt;&#x2F;code&gt;, defined
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;include&#x2F;linux&#x2F;signal.h#L419&quot;&gt;here&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#define&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; SIG_KERNEL_ONLY_MASK&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;	rt_sigmask&lt;&#x2F;span&gt;&lt;span&gt;(SIGKILL)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;   |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  rt_sigmask&lt;&#x2F;span&gt;&lt;span&gt;(SIGSTOP))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So, if we &lt;em&gt;change&lt;&#x2F;em&gt; that definition… we would no longer be treating &lt;code&gt;SIGKILL&lt;&#x2F;code&gt;
and &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt; differently anywhere that this is used:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#ifdef&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; CONFIG_KILL_STOP_HANDLING&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#define&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; SIG_KERNEL_ONLY_MASK&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#define&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; SIG_KERNEL_ONLY_MASK&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; 	rt_sigmask&lt;&#x2F;span&gt;&lt;span&gt;(SIGKILL)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;   |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  rt_sigmask&lt;&#x2F;span&gt;&lt;span&gt;(SIGSTOP))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#endif&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; &#x2F;&#x2F; CONFIG_KILL_STOP_HANDLING&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Conveniently, there are multiple places in &lt;code&gt;kernel&#x2F;signal.c&lt;&#x2F;code&gt; where
&lt;code&gt;sig_kernel_only&lt;&#x2F;code&gt; is used:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L91&quot;&gt;&lt;code&gt;sig_task_ignored&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, when determining whether to send the signal being sent to the task if it is the global init process&lt;&#x2F;li&gt;
&lt;li&gt;in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L2962&quot;&gt;&lt;code&gt;get_signal&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, to also prevent global init and container inits from receiving unwanted signals&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;With this change, when a new handler is to be set from userspace, we will no
longer reject the attempt if the target signal is &lt;code&gt;SIGKILL&lt;&#x2F;code&gt; or &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Signal_Waiting&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Signal_Waiting&quot; aria-label=&quot;Anchor link for: Signal_Waiting&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
Signal Waiting&lt;&#x2F;h3&gt;
&lt;p&gt;There is one last syscall that needs to change its behaviour regarding signals:
&lt;code&gt;timedwait&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L3806&quot;&gt;&lt;code&gt;rt_sigtimedwait&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
lets a process synchronously waits for one of the provided signals to become
&lt;em&gt;pending&lt;&#x2F;em&gt; (i.e. in queue). It then performs some checks, and goes into
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L3747&quot;&gt;&lt;code&gt;do_sigtimedwait&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.
A process is also not allowed to &lt;em&gt;wait&lt;&#x2F;em&gt; for &lt;code&gt;SIGKILL&lt;&#x2F;code&gt; or &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt;, because it
is not supposed to react to these signals. Consequently, the set of signals to
wait for is deprived of these two signals at the start of &lt;code&gt;do_sigtimedwait&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;static int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; do_sigtimedwait&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; sigset_t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;which&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; kernel_siginfo_t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;info&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;		    const struct&lt;&#x2F;span&gt;&lt;span&gt; timespec64 &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;ts&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;	ktime_t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span&gt;to &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; NULL&lt;&#x2F;span&gt;&lt;span&gt;, timeout &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; KTIME_MAX;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;	struct&lt;&#x2F;span&gt;&lt;span&gt; task_struct &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;tsk &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; current;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;	sigset_t&lt;&#x2F;span&gt;&lt;span&gt; mask &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;= *&lt;&#x2F;span&gt;&lt;span&gt;which;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;	enum&lt;&#x2F;span&gt;&lt;span&gt; pid_type type;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;	int&lt;&#x2F;span&gt;&lt;span&gt; sig, ret &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;	if&lt;&#x2F;span&gt;&lt;span&gt; (ts) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;		if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;timespec64_valid&lt;&#x2F;span&gt;&lt;span&gt;(ts))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;			return -&lt;&#x2F;span&gt;&lt;span&gt;EINVAL;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		timeout &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; timespec64_to_ktime&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;ts);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		to &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;= &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;timeout;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;	&#x2F;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;	 * Invert the set of allowed signals to get those we want to block.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;	 *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;	sigdelsetmask&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;mask,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sigmask&lt;&#x2F;span&gt;&lt;span&gt;(SIGKILL)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sigmask&lt;&#x2F;span&gt;&lt;span&gt;(SIGSTOP));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;	signotset&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;mask);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;	spin_lock_irq&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;tsk-&amp;gt;sighand-&amp;gt;siglock);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	sig &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; dequeue_signal&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;mask, info,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;type);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;	&#x2F;&#x2F; ... bla bla bla&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The set of signals to wait for is inverted, and provided to &lt;code&gt;dequeue_signal&lt;&#x2F;code&gt;.
That function waits for a signal &lt;em&gt;not&lt;&#x2F;em&gt; in the set, and returns it. Changing the
line removing our two signals is all we need to remove the second to last
reference to &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt; in &lt;code&gt;kernel&#x2F;signal.c&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#ifndef&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; CONFIG_KILL_STOP_HANDLING&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;	sigdelsetmask&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;mask&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sigmask&lt;&#x2F;span&gt;&lt;span&gt;(SIGKILL)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sigmask&lt;&#x2F;span&gt;&lt;span&gt;(SIGSTOP));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#endif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;Signal_Retrieval_Stage&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Signal_Retrieval_Stage&quot; aria-label=&quot;Anchor link for: Signal_Retrieval_Stage&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
Signal Retrieval Stage&lt;&#x2F;h3&gt;
&lt;p&gt;As mentioned before, the first thing done when a signal is pending is calling
&lt;code&gt;get_signal&lt;&#x2F;code&gt;. In the main loop, the handler is retrieved. If no handler is
present, we keep applying defaults. For all stopping signals, this is done here:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sig_kernel_stop&lt;&#x2F;span&gt;&lt;span&gt;(signr)) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     * The default action is to stop all threads in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     * the thread group.  The job control signals&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     * do nothing in an orphaned pgrp, but SIGSTOP&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     * always works.  Note that siglock needs to be&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     * dropped during the call to is_orphaned_pgrp()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     * because of lock ordering with tasklist_lock.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     * This allows an intervening SIGCONT to be posted.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     * We need to check for that and bail out if necessary.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; (signr &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;!=&lt;&#x2F;span&gt;&lt;span&gt; SIGSTOP) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        spin_unlock_irq&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;sighand-&amp;gt;siglock);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        &#x2F;* signals can be posted during this window *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;is_current_pgrp_orphaned&lt;&#x2F;span&gt;&lt;span&gt;())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            goto&lt;&#x2F;span&gt;&lt;span&gt; relock;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        spin_lock_irq&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;sighand-&amp;gt;siglock);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;likely&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;do_signal_stop&lt;&#x2F;span&gt;&lt;span&gt;(signr))) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        &#x2F;* It released the siglock.  *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        goto&lt;&#x2F;span&gt;&lt;span&gt; relock;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     * We didn&amp;#39;t actually stop, due to a race&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     * with SIGCONT or something like that.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    continue&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here, &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt; is treated differently from other signals because it
&lt;em&gt;supposedly&lt;&#x2F;em&gt; always works. In our world, it does not, so it will have the same
behaviour as other stop signals on those orphaned pgrps:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     * The default action is to stop all threads in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     * the thread group.  The job control signals&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     * do nothing in an orphaned pgrp, but SIGSTOP&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     * always works.  Note that siglock needs to be&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     * dropped during the call to is_orphaned_pgrp()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     * because of lock ordering with tasklist_lock.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     * This allows an intervening SIGCONT to be posted.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     * We need to check for that and bail out if necessary.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;     *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#ifndef&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; CONFIG_KILL_STOP_HANDLING&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; (signr &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;!=&lt;&#x2F;span&gt;&lt;span&gt; SIGSTOP) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#endif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    spin_unlock_irq&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;sighand&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;siglock&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;* signals can be posted during this window *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;is_current_pgrp_orphaned&lt;&#x2F;span&gt;&lt;span&gt;())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        goto&lt;&#x2F;span&gt;&lt;span&gt; relock;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    spin_lock_irq&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;sighand&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;siglock&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#ifndef&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; CONFIG_KILL_STOP_HANDLING&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#endif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And that’s it.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Building,_Booting&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Building,_Booting&quot; aria-label=&quot;Anchor link for: Building,_Booting&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
Building, Booting&lt;&#x2F;h3&gt;
&lt;p&gt;Now, with our kernel done, i just run:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.&#x2F;scripts&#x2F;config -e CONFIG_KILL_STOP_HANDLING&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;make bzImage modules&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo make headers_install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo make modules_install INSTALL_MOD_STRIP=1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo cp arch&#x2F;x86_64&#x2F;boot&#x2F;bzImage &#x2F;boot&#x2F;vmlinuz-killstop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Remember, &lt;a href=&quot;&#x2F;blog&#x2F;irregular-reminder-kernel-install-mod-strip&#x2F;&quot;&gt;always strip your modules in
production&lt;&#x2F;a&gt;. i also
preemptively went in to disable &lt;code&gt;CONFIG_LOCALVERSION_AUTO&lt;&#x2F;code&gt;, and set
&lt;code&gt;CONFIG_LOCALVERSION&lt;&#x2F;code&gt; to &lt;code&gt;&quot;-killstop&quot;&lt;&#x2F;code&gt;, to better identify this kernel. i built
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;Lymkwi&#x2F;linux&#x2F;src&#x2F;branch&#x2F;handle-kill-stop&quot;&gt;my
mod&lt;&#x2F;a&gt;
over a Linux 6.13.0 tree straight from the repos of Linus Torvalds himself.&lt;&#x2F;p&gt;
&lt;p&gt;As i am on Arch Linux, i run a good old &lt;code&gt;sudo mkinitcpio -g &#x2F;boot&#x2F;initramfs-killstop.img --kernelimage &#x2F;boot&#x2F;vmlinuz-killstop -k 6.13.0-killstop-dirty&lt;&#x2F;code&gt;,
then &lt;code&gt;sudo grub-mkconfig -o &#x2F;boot&#x2F;grub&#x2F;grub.cfg&lt;&#x2F;code&gt;, cross the fingers on my paws,
and reboot.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h1 id=&quot;Finding_Out:_Booting_My_Modded_Linux&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Finding_Out:_Booting_My_Modded_Linux&quot; aria-label=&quot;Anchor link for: Finding_Out:_Booting_My_Modded_Linux&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Finding Out: Booting My Modded Linux&lt;&#x2F;h1&gt;
&lt;p&gt;i booted. And nothing happened. Nothing dramatically exploded. Nothing stopped.
Everything was normal. i had booted on the stock Arch Linux by accident while
running back to my bedroom to grab the dog collar that holds my authentication
token.&lt;&#x2F;p&gt;
&lt;p&gt;The second time around, i booted, and nothing happened. Nothing dramatically
exploded, nothing stopped. Everything was normal. i ran &lt;code&gt;uname -r&lt;&#x2F;code&gt; and was
greeted by&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6.13.0-killstop-dirty&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;i was in.&lt;&#x2F;p&gt;
&lt;p&gt;Manipulating signals in Linux userland programs feel somewhat archaic. They kind
of &lt;em&gt;are&lt;&#x2F;em&gt; in a sense. The functions you are supposed to use differ a lot from
those i was taught in college. In fact, the ones i used here are much more
convenient and stick with the conventions of the syscalls. They are found in
&lt;code&gt;signal.h&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Now, i want to write a program that can do one of two things: mask or handle
&lt;code&gt;SIGINT&lt;&#x2F;code&gt;, &lt;code&gt;SIGKILL&lt;&#x2F;code&gt;, &lt;code&gt;SIGSEGV&lt;&#x2F;code&gt;, &lt;code&gt;SIGTERM&lt;&#x2F;code&gt; and &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt;. i am leaving &lt;code&gt;SIGUSR1&lt;&#x2F;code&gt;
and &lt;code&gt;SIGHUP&lt;&#x2F;code&gt; to still have an out to kill my program. i will have a &lt;code&gt;main&lt;&#x2F;code&gt;, and
i can write either &lt;code&gt;mask()&lt;&#x2F;code&gt; or &lt;code&gt;handle()&lt;&#x2F;code&gt; in it to pick what i do.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;handle()&lt;&#x2F;code&gt; function, as well as some boilerplate for later, look like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; forever&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    while&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; setup_handlers&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    signal&lt;&#x2F;span&gt;&lt;span&gt;(SIGINT, catch_function);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    signal&lt;&#x2F;span&gt;&lt;span&gt;(SIGKILL, catch_function);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    signal&lt;&#x2F;span&gt;&lt;span&gt;(SIGSEGV, catch_function);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    signal&lt;&#x2F;span&gt;&lt;span&gt;(SIGTERM, catch_function);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    signal&lt;&#x2F;span&gt;&lt;span&gt;(SIGSTOP, catch_function);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; i never actually check it worked, but, eh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    printf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Successfully set handler for signal numbers &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; and &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;%d\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                SIGINT, SIGKILL, SIGSEGV, SIGTERM, SIGSTOP);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; please_kill&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    unsigned int&lt;&#x2F;span&gt;&lt;span&gt; pid &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; getpid&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    printf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Please run:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\n\t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;kill -9 &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;; kill -11 &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;; kill &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;; kill -19 &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                pid, pid, pid, pid);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; handle&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    setup_handler&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    please_kill&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    forever&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span&gt; EXIT_SUCCESS;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;First we setup handlers for all our signals and point to &lt;code&gt;catch_function&lt;&#x2F;code&gt;, shown
below, using &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;man.archlinux.org&#x2F;man&#x2F;signal.2&quot;&gt;&lt;code&gt;signal&lt;&#x2F;code&gt;(2)&lt;&#x2F;a&gt;. Then, we simply get the &lt;code&gt;pid&lt;&#x2F;code&gt; of the process with
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;man.archlinux.org&#x2F;man&#x2F;getpid.2&quot;&gt;&lt;code&gt;getpid&lt;&#x2F;code&gt;(2)&lt;&#x2F;a&gt; from &lt;code&gt;unistd.h&lt;&#x2F;code&gt;, and prompt the user to &lt;del&gt;wreck the shit out of&lt;&#x2F;del&gt; give all they can to kill the
current process. Finally, we spin forever. If for some reason that loop ends, we
exit successfully.&lt;&#x2F;p&gt;
&lt;p&gt;The catch function will have customized messages for every single one of the
POSIX signals we catch:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;static void&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; catch_function&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; signo&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    status &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; signo;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    switch&lt;&#x2F;span&gt;&lt;span&gt; (signo) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        case&lt;&#x2F;span&gt;&lt;span&gt; SIGINT:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            fputs&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;awawa! x3 you touched my SIGINT~&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, stderr);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            break&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        case&lt;&#x2F;span&gt;&lt;span&gt; SIGKILL:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            fputs&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;awawawawa :3 you tried to SIGKILL me~ teehee~&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, stderr);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            break&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        case&lt;&#x2F;span&gt;&lt;span&gt; SIGSEGV:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            fputs&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;ouchies! my memory SIGSEGVd x3!&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, stderr);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            break&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        case&lt;&#x2F;span&gt;&lt;span&gt; SIGTERM:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            fputs&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;i&amp;#39;m not gonna SIGTERM, meaning! &amp;gt;:3c&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, stderr);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            break&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        case&lt;&#x2F;span&gt;&lt;span&gt; SIGSTOP:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            fputs&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;owo *notices your SIGSTOP*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, stderr);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            break&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        default&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            break&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For &lt;em&gt;masking&lt;&#x2F;em&gt;, we use &lt;code&gt;sigset_t&lt;&#x2F;code&gt; to create a set of signals. &lt;strong&gt;It is very
important to call
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;man.archlinux.org&#x2F;man&#x2F;sigemptyset.3&quot;&gt;&lt;code&gt;sigemptyset&lt;&#x2F;code&gt;(3)&lt;&#x2F;a&gt; or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;man.archlinux.org&#x2F;man&#x2F;sigfillset.3&quot;&gt;&lt;code&gt;sigfillset&lt;&#x2F;code&gt;(3)&lt;&#x2F;a&gt; on it&lt;&#x2F;strong&gt;, or you will suffer the wrath of
uninitialized memory:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;sigset_t&lt;&#x2F;span&gt;&lt;span&gt; mask, old;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sigemptyset&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;mask&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sigemptyset&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;old&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, i add the signals i want in my set with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;man.archlinux.org&#x2F;man&#x2F;sigaddset.3&quot;&gt;&lt;code&gt;sigaddset&lt;&#x2F;code&gt;(3)&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sigaddset&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;mask&lt;&#x2F;span&gt;&lt;span&gt;, SIGINT);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sigaddset&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;mask&lt;&#x2F;span&gt;&lt;span&gt;, SIGKILL);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sigaddset&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;mask&lt;&#x2F;span&gt;&lt;span&gt;, SIGSEGV);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sigaddset&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;mask&lt;&#x2F;span&gt;&lt;span&gt;, SIGTERM);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sigaddset&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;mask&lt;&#x2F;span&gt;&lt;span&gt;, SIGSTOP);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;i then call &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;man.archlinux.org&#x2F;man&#x2F;sigprocmask.2&quot;&gt;&lt;code&gt;sigprocmask&lt;&#x2F;code&gt;(2)&lt;&#x2F;a&gt; using that set:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; ((res &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; sigprocmask&lt;&#x2F;span&gt;&lt;span&gt;(SIG_BLOCK,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;mask&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;old&lt;&#x2F;span&gt;&lt;span&gt;))&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    fprintf&lt;&#x2F;span&gt;&lt;span&gt;(stderr,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Error masking away signals: &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;%d\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, res);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    return -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;i then call &lt;code&gt;please_kill()&lt;&#x2F;code&gt; the same way i do for signal handling before, so
that i can prompt my user to kill my process in many colourful ways, then spin
forever.&lt;&#x2F;p&gt;
&lt;p&gt;The result, at least for signal handling, is something like
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eldritch.cafe&#x2F;@SharpLimefox&#x2F;113976467185768571&quot;&gt;this&lt;&#x2F;a&gt;: a process that
can handle, for example, &lt;code&gt;SIGKILL&lt;&#x2F;code&gt;. As a result, conventional means of killing a
program are completely ineffective against it, as expected.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;video style=&quot;margin-left: auto; margin-right: auto; display: block;&quot; aria-label=&quot;screen recording of two terminals, one with a program running and the other where i run `kill` to terminate it. The program has signal handlers for SIGINT, SIGKILL, SIGSEGV, SIGTERM and SIGSTOP, so nothing reacts&quot; title=&quot;screen recording of two terminals, one with a program running and the other where i run `kill` to terminate it. The program has signal handlers for SIGINT, SIGKILL, SIGSEGV, SIGTERM and SIGSTOP, so nothing reacts&quot; lang=&quot;en&quot; role=&quot;application&quot; src=&quot;https:&#x2F;&#x2F;eldritchcafe.files.fedi.monster&#x2F;media_attachments&#x2F;files&#x2F;113&#x2F;976&#x2F;455&#x2F;451&#x2F;339&#x2F;528&#x2F;original&#x2F;c0c639e4ef6fac99.mp4&quot; controls=&quot;&quot; playsinline=&quot;&quot;&gt;&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Conclusion&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Conclusion&quot; aria-label=&quot;Anchor link for: Conclusion&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Conclusion&lt;&#x2F;h1&gt;
&lt;p&gt;There are many things i haven’t touched on. &lt;code&gt;SIGSTOP&lt;&#x2F;code&gt; is actually referenced &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;C&#x2F;ident&#x2F;SIGSTOP&quot;&gt;a
whole lot&lt;&#x2F;a&gt;, and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;C&#x2F;ident&#x2F;SIGKILL&quot;&gt;same
for &lt;code&gt;SIGKILL&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. i
figured the files i touched are the part i was mostly interested in, but other
things could be worth looking into. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;man.archlinux.org&#x2F;man&#x2F;ptrace.2&quot;&gt;&lt;code&gt;ptrace&lt;&#x2F;code&gt;(2)&lt;&#x2F;a&gt; reacts on signals, so does
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;man.archlinux.org&#x2F;man&#x2F;strace.1&quot;&gt;&lt;code&gt;strace&lt;&#x2F;code&gt;(1)&lt;&#x2F;a&gt;. There are &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c#L905&quot;&gt;specific trap
invocations&lt;&#x2F;a&gt;
that are supposed to notify &lt;code&gt;ptrace&lt;&#x2F;code&gt; upon signals being fired, and all kinds of
things. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;fs&#x2F;signalfd.c&quot;&gt;signalfd&lt;&#x2F;a&gt;
is something i could have looked into as well, but i did not. &lt;code&gt;kernel&#x2F;ptrace.c&lt;&#x2F;code&gt;
also &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;ptrace.c#L1089&quot;&gt;sometimes explicitly singles out kernel signals&lt;&#x2F;a&gt; for some actions. By all means, my patches are not complete. Yet, they will let you do
what i set out to do when i started this: handle and mask the two signals that
nobody is supposed to mask or handle.&lt;&#x2F;p&gt;
&lt;p&gt;And you know? It turned out fine. Nothing exploded on my system. As i could
predict, because this was otherwise &lt;em&gt;impossible&lt;&#x2F;em&gt;, nobody did it. The signal
system was setup in such a way that you would most likely realize something you
were doing was &lt;em&gt;wrong&lt;&#x2F;em&gt;, and not try it.&lt;&#x2F;p&gt;
&lt;p&gt;To pull back further, it is interesting to notice how the rules we all take for
granted are just &lt;em&gt;set somewhere&lt;&#x2F;em&gt; in code. They were written by someone, at some
point. If there is code restricting you from doing something, someone wrote it.
Either they did not think anyone would want to do that thing, or they
specifically prevented you from doing it. Those rules are written somewhere, and
you can take it in your paws to go sniff around the code, pull out the relevant
parts, and hack around the things that bother you. For fun, learning, or
convenience.&lt;&#x2F;p&gt;
&lt;p&gt;Snoop around. Sniff code. Put your paws in it. Hack shit.&lt;&#x2F;p&gt;
&lt;!--As a fun little bonus, i modified my signals program to mask **all** signals,
including `SIGHUP`. It is still running as i write this.--&gt;
&lt;br&gt;
&lt;hr &#x2F;&gt;
&lt;h1 id=&quot;See_Also&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#See_Also&quot; aria-label=&quot;Anchor link for: See_Also&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
See Also&lt;&#x2F;h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;man.archlinux.org&#x2F;man&#x2F;signal.7&quot;&gt;&lt;code&gt;signal&lt;&#x2F;code&gt;(7)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.13&#x2F;source&#x2F;kernel&#x2F;signal.c&quot;&gt;&lt;code&gt;kernel&#x2F;signal.c&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;C_signal_handling&quot;&gt;C Signal Handling - Wikipedia&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;35569659&#x2F;the-signals-sigkill-and-sigstop-cannot-be-caught-blocked-or-ignored-why&quot;&gt;“The signals SIGKILL and SIGSTOP cannot be caught, blocked or ignored, why?” - StackOverflow&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Signal_(IPC)&quot;&gt;Signal (IPC) - Wikipedia&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;filippo.io&#x2F;linux-syscall-table&#x2F;&quot;&gt;Searchable Linux Syscall Table&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;IEEE Standard 1003.1-2024 &#x2F; POSIX 2024 (you can browse or download an HTML version &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pubs.opengroup.org&#x2F;onlinepubs&#x2F;9799919799&#x2F;&quot;&gt;here&lt;&#x2F;a&gt; or ask me for a PDF)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;!--
vim: set cc=80 tw=80 spell:
--&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Radio Listening: Airplanes</title>
        <published>2025-01-27T00:00:00+00:00</published>
        <updated>2025-01-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/rf-series-airplanes/"/>
        <id>https://vulpinecitrus.info/blog/rf-series-airplanes/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/rf-series-airplanes/">&lt;p&gt;After i received the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.rtl-sdr.com&#x2F;V4&#x2F;&quot;&gt;kit i ordered&lt;&#x2F;a&gt;, i fiddled
around with software, eventually figuring out i would install
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;sdrpp.org&#x2F;&quot;&gt;SDR++&lt;&#x2F;a&gt; (though SDR# and sdrangel are also good picks). I
sat down, got a feel for the controls, installed a frequency band plan made
by a French person, and started listening to the 120MHz-137MHz band, in AM mode.
After a little while, spikes appeared. i happen to live not too far to an
airport with a somewhat busy schedule, and i quickly figured out what was
happening.&lt;&#x2F;p&gt;
&lt;p&gt;This post goes over everything i have learned to do to listen to and track
airplanes and airports, so that you too can know these things and do them
(&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.gesetze-im-internet.de&#x2F;ttdsg&#x2F;__5.html&quot;&gt;unless you are German, apparently&lt;&#x2F;a&gt;).
There’s one caveat, however, which is that while EU air traffic control has one
common regulator (EUROCONTROL), ATC might look different in other places (or
even differ slightly from one locality to another).&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Voice_Communication&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Voice_Communication&quot; aria-label=&quot;Anchor link for: Voice_Communication&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Voice Communication&lt;&#x2F;h1&gt;
&lt;p&gt;Airplanes and airports communicate via radio waves.&lt;&#x2F;p&gt;
&lt;p&gt;Medium-sized and big airports will typically have a &lt;em&gt;air control tower&lt;&#x2F;em&gt;, with
people working in there to communicate with individual airplanes, and broadcast
information. There are also coordination centers across the country that operate
communications. For clarity, i’ll call people in there “controllers”, regardless
of the different positions they can have.&lt;&#x2F;p&gt;
&lt;p&gt;Voice information broadcast happens via AM mode, on a band between 118 MHz and
137 MHz, with a 10 KHz bandwidth. One consequence of the use of AM is that the
voice signal can travel &lt;em&gt;quite far away&lt;&#x2F;em&gt; as long as the plane is in the air
(where you are very likely to have line of sight even tens of kilometers away).&lt;&#x2F;p&gt;
&lt;p&gt;Airports will typically have multiple frequencies for airplanes &lt;em&gt;coming into the
airspace&lt;&#x2F;em&gt; or &lt;em&gt;needing information&lt;&#x2F;em&gt; or &lt;em&gt;needing to negotiate&lt;&#x2F;em&gt; with controllers.
The first of these sets of frequencies is called &lt;em&gt;Approach frequencies&lt;&#x2F;em&gt;. The
next ones are typically called &lt;em&gt;ATIS&lt;&#x2F;em&gt;, or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Automatic_terminal_information_service&quot;&gt;Automatic Terminal Information
Service&lt;&#x2F;a&gt;.
The last ones are tower frequencies. Those are not the only types that exist, by
any mean (depending on the airport there are others such as for taxiing on the
apron, the area around gates, etc, and for passing way above the airport where
you could not reasonably inconvenience anyone). As i have been informed, some of
these frequencies are managed by the local airport, and some by the coordination
centers in charge of air traffic control across the country.&lt;&#x2F;p&gt;
&lt;p&gt;When planes are about to enter the airspace of a nearby airport for landing,
they need to announce themselves to the controllers via the dedicated frequency.
In big airports, multiple of those can exist, and the appropriate one is picked
depending on your hardware, your location, or other circumstances. Here at LFRN
(the airport in Rennes, France), the distinction seems to be depending on your
&lt;em&gt;area&lt;&#x2F;em&gt; of approach. Despite that, i have only ever heard one of the frequencies
used (perhaps because of my direction with the airport). The pilot does not pick
themselves however. What happens from their point of view is that the last
controller they talk to before approaching the airport will tell them what
frequency to tune in for approach before leaving them.&lt;&#x2F;p&gt;
&lt;p&gt;When planes want information about the state of an airport, they tune into the
airport’s ATIS frequency (for the language they want, if multiple are
available). The ATIS frequencies broadcast voice recordings&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-atis-digital-1&quot;&gt;&lt;a href=&quot;#fn-atis-digital&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
summing up a lot of information about the different runways, weather
information, etc. Did you know that, as of October 2024, the ATIS for
Charles-de-Gaulle and Orly airport, in Paris, use Text-to-speech for all
languages? Now you do. Over where i live, LFRN uses a loop of a recorded human
voice.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, when planes need to negotiate with controllers to take off, land, or
move around on the ground, they communicate on the &lt;em&gt;Tower&lt;&#x2F;em&gt; frequencies. This is
where the bulk of activity will usually happen when you’re next to a
medium-sized airport. Every time an airplane takes off or lands, you will be
able to hear a whole exchange giving landing authorization, or asking to loop
around to wait. Controllers will provide direction, weather information, etc.
They will also indicate what taxiway to take to exit the runway, and so on.&lt;&#x2F;p&gt;
&lt;p&gt;In all of these situations, the language used is fairly codified. This is done
both for making sure everyone understands each other, but also for clarity: AM
radio goes far away, but voice quality is shoddy. Telling apart a German saying
“Nein” and an English-speaker saying “Nine” is hard, so we say “Niner” instead
for the digit.&lt;&#x2F;p&gt;
&lt;p&gt;As an example, here is a small sample of a conversation between controllers at
LFRN and a plane landing, roughly translated to English:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Controller&lt;&#x2F;strong&gt;: 80 44 Rennes good evening, runway 28 landing authorized, wind 180&lt;&#x2F;p&gt;
&lt;p&gt;degrees, 16 to 22 knots, runway is wet&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;plane (FMY8044)&lt;&#x2F;strong&gt;: landing authorized 28, runway wet, FMY 8044&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Controller&lt;&#x2F;strong&gt;: 8044 exit runway first left via delta, drive to ALAT parking,
listen to 121 decimal 7 2 5 and call back when runway cleared&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;plane (FMY8044)&lt;&#x2F;strong&gt;: we’re driving to ALAT, 121 7 2 5 and call back when runway
cleared. FMY8044&lt;&#x2F;p&gt;
&lt;p&gt;plane: (FMY8044): Runway cleared, end of service 8044.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Controller&lt;&#x2F;strong&gt;: Received 8044, call back ALAT for exit.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;plane (FMY8044)&lt;&#x2F;strong&gt;: We will call ALAT for exit. FMY 8044.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;When a plane receives orders, they will have to repeat the information to tell
controllers that it was understood. Similarly, when they enter an airspace, they
must announce themselves. Otherwise, the pilot will quickly start noticing that
a fighter tail is telling them, and they should expect to be arrested and
stripped of their license immediately after landing. In the exchanges above,
plane &lt;code&gt;FMY8044&lt;&#x2F;code&gt; received authorization to land, as well as information about
wind and runway conditions. They acknowledged back. The controllers then told
them what &lt;em&gt;taxiway&lt;&#x2F;em&gt; to use to exit the runway through, and where to go and what
frequency to listen for information. Controllers tell the plane to call them
back when the runway is cleared, which they do later, announcing the end of
their service for the day. Controllers announce who they need to call to exit
the taxiways, and they acknowledge, repeating their call sign every time
(although i could not hear the start properly so i just pasted FMY8044 in its
entirety, they tend to shorten them as does the controller). For context, ALAT
is the acronym of &lt;em&gt;Aviation Légère de l’Armée de Terre&lt;&#x2F;em&gt;, or lightweight aviation
division of the french ground army. Do of that information what you will.&lt;&#x2F;p&gt;
&lt;p&gt;Now, in terms of voice communications i also receive next to an airport, tower
controllers can also communicate with marshallers (the french call them
“sécurité” but they are not exactly security, more like on-ground personnel on
the runways making sure everything goes correctly). They may be tasked with
doing sweeps of the runways, guide airplanes to follow them, etc. Sometimes they
also get to hold glowing sticks. Neat. The marshallers team at my airport once
had a very confused discussion with controllers after a departing airplane
&lt;em&gt;absolutely bodied a seagull&lt;&#x2F;em&gt;. They retrieved the corpse of the poor thing, of
course. In order to do that, even &lt;em&gt;they&lt;&#x2F;em&gt; had to get permission from Tower to
move around. In that situation, airplanes always have the right of way, even in
an emergency.&lt;&#x2F;p&gt;
&lt;p&gt;And how do you what frequencies correspond to which airport and vice versa?
Pilots have documents for that purpose, and complicated instruments. i
personally have &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;skyvector.com&#x2F;&quot;&gt;SkyVector&lt;&#x2F;a&gt;, a global database of
airport information. Say you want to tune into the french-speaking ATIS for
Lyon’s LFLL, aka &lt;em&gt;Lyon Saint-Exupery&lt;&#x2F;em&gt;, you’d read that it is at &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;skyvector.com&#x2F;airport&#x2F;LFLL&#x2F;Lyon-Saint-Exupery-Airport&quot;&gt;126.18
MHz&lt;&#x2F;a&gt;. Tune your
SDR, deploy a roughly 60cm long straight dipole antenna looking at the airport,
and boom: you have audio of people talking.&lt;&#x2F;p&gt;
&lt;p&gt;Now, receiving voice is harder when you are far from an airport. Receiving voice
from airplanes is easier, but they need to be somewhat close to somewhere that
needs them to talk in order for any speech to happen.&lt;&#x2F;p&gt;
&lt;p&gt;Most of what i talked about here also apply to small aviation clubs, especially
as they depend on a local airport for operating. The aviation club in my city
also talks with controllers, and uses the same runways and taxiways as
commercial airplanes. From the interactions i have heard, i am fairly sure they
know each other.&lt;&#x2F;p&gt;
&lt;p&gt;And that’s roughly it for voice. It is not &lt;em&gt;technically&lt;&#x2F;em&gt; complex to listen to
airplanes. If you do not live next to an airport, websites such as
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.liveatc.net&#x2F;&quot;&gt;LiveATC&lt;&#x2F;a&gt; offer you archives and live audio of air
traffic control frequencies (except in Germany, of course, because Germany is
spiritually opposed to people having fun).&lt;&#x2F;p&gt;
&lt;p&gt;But in order to know what airplanes are up to, you kind of need to know &lt;em&gt;where&lt;&#x2F;em&gt;
they are? Don’t worry, i also got you covered.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Aircraft_Transponders&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Aircraft_Transponders&quot; aria-label=&quot;Anchor link for: Aircraft_Transponders&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Aircraft Transponders&lt;&#x2F;h1&gt;
&lt;p&gt;Airborne vessels of basically all kinds need to tell the ground and others
flying &lt;em&gt;where&lt;&#x2F;em&gt; they are, at least in terms more precise than “above you, silly”.&lt;&#x2F;p&gt;
&lt;p&gt;They are equipped with &lt;em&gt;transponders&lt;&#x2F;em&gt;. These things will just broadcast
information about the vessel including: flight number, aircraft altitude,
heading, latitude, longitude, and status code (also called &lt;em&gt;squawk&lt;&#x2F;em&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;These transponders mostly use the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.sigidwiki.com&#x2F;wiki&#x2F;ADS-B&quot;&gt;Automatic Dependent System Broadcast
(ADS-B)&lt;&#x2F;a&gt; protocol in Europe and Northern
America, at least. In Europe, planes broadcast information at &lt;em&gt;1090 MHz&lt;&#x2F;em&gt;.
Americans are incapable of managing their band plans and, therefore, they have
ADS-B at 978 MHz, which once raised concerns about cellular
phones&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-airplane-mode-1&quot;&gt;&lt;a href=&quot;#fn-airplane-mode&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;!--https:&#x2F;&#x2F;www.livescience.com&#x2F;5947-real-reason-cell-phone-banned-airlines.html--&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;vulpinecitrus.info&#x2F;blog&#x2F;rf-series-airplanes&#x2F;.&#x2F;ads-b_sdrpp.jpg&quot; alt=&quot;ADS-B signal as seen in SDR++&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#&quot; aria-label=&quot;Anchor link for: &quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
ADS-B Antenna Setup&lt;&#x2F;h2&gt;
&lt;p&gt;My own setup for listening to ADS-B uses the following items:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;RTL-SDR dongle&lt;&#x2F;li&gt;
&lt;li&gt;Wideband Low-Noise Amplifier (i could use the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.rtl-sdr.com&#x2F;new-product-rtl-sdr-blog-1090-mhz-ads-b-lna&#x2F;&quot;&gt;ADS-B specific one sold by
RTL-SDR&lt;&#x2F;a&gt;,
but i only have the wideband variant)&lt;&#x2F;li&gt;
&lt;li&gt;Antenna kit: small antenna set, pulled all the way out, in a straight dipole&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Optionally, i also add a reflector. This can be any plate of metal, or an
aluminium sheet behind the antenna in the direction you target. Because i have
immense brainrot and find it pleasant to be treated like an animal by others, i
even have my own &lt;em&gt;para-bowl-ic&lt;&#x2F;em&gt; antenna:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;vulpinecitrus.info&#x2F;blog&#x2F;rf-series-airplanes&#x2F;.&#x2F;bowl_antenna.jpg&quot; alt=&quot;“The puppy bowl antenna reflector”&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;-1&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#-1&quot; aria-label=&quot;Anchor link for: -1&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Listening to Transponders&lt;&#x2F;h2&gt;
&lt;p&gt;ADS-B carries a ton of information, as stated above. Because it is transmitted
in the UHF range, the signal penetrates buildings pretty badly. Several tools
available online allow you to receive and decode ADS-B on 1090 MHz. The keyword
to search for them is usually something like “1090”. Personally, i tried
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;wiedehopf&#x2F;readsb&quot;&gt;&lt;code&gt;readsb&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;,
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;osmocom&#x2F;rtl-sdr&#x2F;blob&#x2F;master&#x2F;src&#x2F;rtl_adsb.c&quot;&gt;&lt;code&gt;rtl_adsb&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;flightaware&#x2F;dump1090&quot;&gt;&lt;code&gt;dump1090&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; (specifically the
FlightAware variant&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-dump1090-forks-1&quot;&gt;&lt;a href=&quot;#fn-dump1090-forks&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;). In the end i kept using &lt;code&gt;dump1090&lt;&#x2F;code&gt;,
because &lt;code&gt;readsb&lt;&#x2F;code&gt; was a pain to get working, and i learned about &lt;code&gt;rtl_adsb&lt;&#x2F;code&gt; after
using &lt;code&gt;dump1090&lt;&#x2F;code&gt; for a while (and the former needs a bit more processing and
software to actually &lt;em&gt;read&lt;&#x2F;em&gt; the ADS-B messages).&lt;&#x2F;p&gt;
&lt;p&gt;For visualization, i initially looked into
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;wiedehopf&#x2F;tar1090&quot;&gt;&lt;code&gt;tar1090&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, but quickly realized that it
is closer in taxonomy to a distribution for creating a small ADS-B collection
computer on a Raspberry Pi or other micro computer rather than a single piece of
software&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-tar1090-1&quot;&gt;&lt;a href=&quot;#fn-tar1090&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. Therefore, i ended up using
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nmatsuda&#x2F;viz1090&quot;&gt;&lt;code&gt;viz1090&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, which despite being more
minimal, actually works with a single small binary i can compile.&lt;&#x2F;p&gt;
&lt;p&gt;First, start running &lt;code&gt;dump1090&lt;&#x2F;code&gt; somewhere. You will need multiple arguments:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dump1090 --net --gnss&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The arguments mean:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--net&lt;&#x2F;code&gt; expose the data via the Beast protocol, by default on &lt;code&gt;127.0.0.1&lt;&#x2F;code&gt; and
a bunch of ports (including &lt;code&gt;30005&lt;&#x2F;code&gt;, the Beast output port)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;--gnss&lt;&#x2F;code&gt; tells the program to resolve altitudes via the Height Above
Ellipsoid (HAE) system (most like WGS84, i assume).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Technically you do not need anything beyond &lt;code&gt;--net&lt;&#x2F;code&gt; for this to work. You can
also add &lt;code&gt;--stats&lt;&#x2F;code&gt;, &lt;code&gt;--stats-range&lt;&#x2F;code&gt; and &lt;code&gt;--stats-every [time]&lt;&#x2F;code&gt; to get stats
about the distance of planes observed when the program exits, and every &lt;code&gt;[time]&lt;&#x2F;code&gt;
seconds, respectively. If you want these statistics, you will need to provide
your reference position using &lt;code&gt;--lat&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;--lon&lt;&#x2F;code&gt;, otherwise &lt;code&gt;dump1090&lt;&#x2F;code&gt; has no idea
where you are located.&lt;&#x2F;p&gt;
&lt;p&gt;If you are using a &lt;em&gt;Low-Noise Amplifier&lt;&#x2F;em&gt; on your transmission line, like i do,
set the gain down at around 28.0 dB, so that the LNA does not saturate your
signal (otherwise you will get nothing). For reference, i went from receiving no
signal when &lt;code&gt;dump1090&lt;&#x2F;code&gt; cranked the gain all the way to maximum with my LNA, to
receiving information about planes 350+km away from me while indoors with
&lt;code&gt;--gain 28.0&lt;&#x2F;code&gt; (or play with it to figure out the sweet spot for your reception
setup).&lt;&#x2F;p&gt;
&lt;p&gt;The output of &lt;code&gt;dump1090&lt;&#x2F;code&gt; should be a stream of messages that look something like
this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*8d4cae4c58c383b3af7f10137192;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CRC: 000000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;RSSI: -24.5 dBFS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Score: 27 (DF17_KNOWN)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Time: 16462495.58us&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DF:17 AA:4CAE4C CA:5 ME:58C383B3AF7F10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Extended Squitter Airborne position (barometric altitude) (11) (reliable)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ICAO Address:  4CAE4C (Mode S &#x2F; ADS-B)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Air&#x2F;Ground:    airborne&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Baro altitude: 38000 ft&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  CPR type:      Airborne&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  CPR odd flag:  even&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  CPR latitude:  47.55281 (121303)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  CPR longitude: -2.26648 (98064)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  CPR decoding:  global&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  NIC:           8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Rc:            0.186 km &#x2F; 0.1 NM&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  NIC-B:         0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*5d4ca80200c875;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CRC: 00000f&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;RSSI: -23.2 dBFS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Score: 20 (DF11_IID_KNOWN)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Time: 16466780.75us&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DF:11 AA:4CA802 IID:15 CA:5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; All Call Reply&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ICAO Address:  4CA802 (Mode S &#x2F; ADS-B)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Air&#x2F;Ground:    airborne&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Some messages carry information about GPS location, some give you the state of
the airplane, etc. All messages are supposed to contain what is called an &lt;em&gt;ICAO
Address&lt;&#x2F;em&gt; (from the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.icao.int&#x2F;&quot;&gt;International Civil Aviation
Organization&lt;&#x2F;a&gt;), which is a unique international
transponder identifier. When you receive these messages correctly, you should
have hundreds of them, or even thousands, flying in your terminal every second.&lt;&#x2F;p&gt;
&lt;p&gt;Now, after &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nmatsuda&#x2F;viz1090?tab=readme-ov-file#building&quot;&gt;building
&lt;code&gt;viz1090&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, you
can run it as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.&#x2F;viz1090 --lat [latitude] --lon [longitude] --metric --fullscreen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--lat&#x2F;--lon&lt;&#x2F;code&gt; as the reference position on start&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;--metric&lt;&#x2F;code&gt; to use units that make sense&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;--fullscreen&lt;&#x2F;code&gt; if you want the resulting window to be fullscreen&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In my case, i see something like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;vulpinecitrus.info&#x2F;blog&#x2F;rf-series-airplanes&#x2F;.&#x2F;ads-b_viz.jpg&quot; alt=&quot;View on &lt;code&gt;viz1090&lt;&#x2F;code&gt;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The different planes that were recently seen are yellow, and they get greyer the
longer you don’t need any message about them. As soon as position data is
received, the plane appears. Information such as flight number, speed, and
altitude, are added and refreshed whenever relevant messages are seen. When that
happens, a circle appears the airplanes.&lt;&#x2F;p&gt;
&lt;p&gt;You can also use &lt;code&gt;view1090&lt;&#x2F;code&gt;, which comes with the &lt;code&gt;dump1090-fa-git&lt;&#x2F;code&gt; AUR package on
Arch Linux:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Tot:  14 Vis:  14 RSSI: Max -24.2+ Mean -31.3 Min -35.1-  MaxD:    0.0nm+     &#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Hex    Mode  Sqwk  Flight   Alt    Spd  Hdg    Lat      Long   RSSI  Msgs  Ti&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;────────────────────────────────────────────────────────────────────────────────&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 406F86 S                                                      -35.1-    7 12&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 346611 A2    2362  VOE2828   2307  548  234   47.121   -1.845 -24.2+  179 01&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 4CA6C4 A0    6324           11278                             -31.2    22 03&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 020095 A2    7154  RAM839J  11880  890  224   45.951   -2.415 -32.4    94 08&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 4952CC S                    11590                             -34.4    13 19&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 44CC42 A0    2364                  805  035                   -34.8    75 21&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 4952C3 A2    2227  TAP76G   11575  781  019   46.988   -2.784 -31.5   280 05&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 47A218 A2    2210  NOZ9034  10661  853  205   47.751   -3.559 -30.9   479 11&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 4CA216 A2    2255  EIN464   11278  803  147   47.713   -2.190 -26.2  2595 00&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 4409C0 A0    7624           10669  877  221   45.661   -2.916 -34.6   182 78&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 48663E A2          TRA46R                                     -34.5   687 80&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 4CA852 A2    7463  RYR5716  10973  764  021   47.342   -2.423 -28.1  2387 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 440185 A2    2356  EJU4787  10951  840  195   45.442   -2.644 -31.2  4607 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 4CADC2 A2    7462  RYR601Y  12184  813  021   48.242   -1.904 -29.3 14201 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here is a little example of many planes, showing their ICAO address, squawk,
flight number, etc. The flight numbers are also transmitted via ADS-B. For
the meaning of squawk numbers, i’d encourage you to go read the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Squawk_code&quot;&gt;Wikipedia
page&lt;&#x2F;a&gt;. Oddly enough, French Wikipedia
has a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;fr.wikipedia.org&#x2F;wiki&#x2F;Transpondeur_(aviation)&quot;&gt;more thorough&lt;&#x2F;a&gt;
list of codes. You can see that some lines are missing information: because all
of the information about a plane is not transmitted at once in every message,
you will get partial information until you receive the rest of the information.
For example, the plane with hexadecimal ICAO address &lt;code&gt;4409C0&lt;&#x2F;code&gt; above does not
show a flight number. Most likely, i just did not receive any message with that
information in the 182 messages i got from that plane (or they were malformed
and useless). Some are missing squawk, some do not have GPS coordinates yet.
Good reception will improve the number of messages correctly decoded, and
increase the amount of information you can get about planes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;-2&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#-2&quot; aria-label=&quot;Anchor link for: -2&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Feeding Global ADS-B Antenna Networks&lt;&#x2F;h2&gt;
&lt;p&gt;Considering that you can receive all of that information on a budget of less
than 40€, it seems natural that people around the world banded together to
crowd-source them.&lt;&#x2F;p&gt;
&lt;p&gt;There are multiple online networks of ADS-B antennas, and even other protocols,
and i haven’t contributed to any yet. It will certainly be a future topic of
investigation on my end, which might warrant a small spin-off post in the
future.&lt;&#x2F;p&gt;
&lt;p&gt;The network i use the most for online plane world maps,
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.flightradar24.com&#x2F;&quot;&gt;FlightRadar24&lt;&#x2F;a&gt;, pools information from around
the world to display a gigantic map and provide archives of plane and flight
information. They even tell you how to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.flightradar24.com&#x2F;build-your-own&quot;&gt;build your own
receiver&lt;&#x2F;a&gt;, and you can even &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.flightradar24.com&#x2F;apply-for-receiver&quot;&gt;apply
to get a free one&lt;&#x2F;a&gt; if you live
in a zone with poor coverage. By contributing data to their network, whether
with your own hardware or not, you can also get their otherwise very expensive
premium plan for free.&lt;&#x2F;p&gt;
&lt;p&gt;i also know of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.flightaware.com&#x2F;&quot;&gt;FlightAware&lt;&#x2F;a&gt;, a multinational
company that operates a similar service to FlightRadar24, at a larger scale,
with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.flightaware.com&#x2F;adsb&#x2F;coverage&#x2F;&quot;&gt;a very large coverage&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;globe.adsbexchange.com&#x2F;&quot;&gt;ADS-B Exchange&lt;&#x2F;a&gt; is another network, with less
paywalls. i haven’t used it as thoroughly as the other two but it seems to have
the basic features of maps, resolving aircraft information, and flight archives.
It runs &lt;code&gt;tar1090&lt;&#x2F;code&gt;, which i mentioned above. It is very decent software and does
its job, although i wish i could switch units from imperial to metric (if i can,
i haven’t found how to yet, and i know pilots use imperial units for elevation).&lt;&#x2F;p&gt;
&lt;h1 id=&quot;-3&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#-3&quot; aria-label=&quot;Anchor link for: -3&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Conclusion&lt;&#x2F;h1&gt;
&lt;p&gt;This is more or less the entire gamut of radio observations possible on
commercial and civilian aircrafts i know of, for now. Military stuff is a little
more complex, even though some of these aircrafts also have regular transponders
that you can also listen to.&lt;&#x2F;p&gt;
&lt;p&gt;i could spend a good amount of time just sitting down, listening to air traffic
control, and vibe. It’s a genuinely pleasant activity. i would, however, not
recommend you pull up next to an airport and get out a big antenna; cops, in
general, really do not like that.&lt;&#x2F;p&gt;
&lt;p&gt;Hopefully you learned something. i glossed over a lot of details for the sake of
readability and not drowning you, the reader, in technical minutiae that you may
not care about. Let me know if this was of any help, or made you learn something
interesting about those flying metal birds in the sky.&lt;&#x2F;p&gt;
&lt;p&gt;I’d like to thank folks who helped me write this post:
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;flufftech.net&quot;&gt;rail&lt;&#x2F;a&gt;, who helped proofread,
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;magiclike.net&quot;&gt;MagicLike&lt;&#x2F;a&gt; for contributing his knowledge about air
traffic control, and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;kloenk.eu&#x2F;&quot;&gt;kloenk&lt;&#x2F;a&gt; for helping me figure out
where the hell German law says you can’t listen to any radio communication you
are not the recipient of.&lt;&#x2F;p&gt;
&lt;!--
vim: set cc=80 tw=80 spell:
--&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-atis-digital&quot;&gt;
&lt;p&gt;There is now a more modern digital ATIS which can apparently be
beamed into airplanes to give them information? Awesome. it seems to use
other means than radio, however. My airport does not advertise digital ATIS,
so i have not looked into it. &lt;a href=&quot;#fr-atis-digital-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-airplane-mode&quot;&gt;
&lt;p&gt;Yes, that’s very close to the E&#x2F;R-GSM-900 bands, for cellphone
data. Yes, that’s one of the reasons &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Airplane_mode&quot;&gt;airplane
mode&lt;&#x2F;a&gt; exists, even though more
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.transportation.gov&#x2F;testimony&#x2F;cell-phones-aircraft-nuisance-or-necessity#:~:text=Cell%20phones%20are%20different%20from,phones%20on%20aircraft%20during%20flight.&quot;&gt;modern standards should not interfere with
transponders&lt;&#x2F;a&gt;,
and even though the concern about interference was apparently always &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20240505193637&#x2F;https:&#x2F;&#x2F;www.tc.faa.gov&#x2F;its&#x2F;worldpac&#x2F;techrpt&#x2F;ar12-30.pdf&quot;&gt;&lt;em&gt;out
of an abundance of
precaution&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;.
That is to say: you do not want to say “it’s unlikely to happen” and then be
in the 1 in a gazillion flight where a concordance of reasons make it so
that vital instruments used for a complicated take-off or landing are jammed
this one time by a group of cellphones conveniently all screaming to connect
to a GSM base transmission station. Still, you should use airplane mode to
save battery and not overload cell towers underneath you with tons of
hand-over requests (unless your plane is designed to include a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gizmodo.com&#x2F;you-don-t-need-to-use-airplane-mode-on-airplanes-1851282769&quot;&gt;cellular
“pico-cell”&lt;&#x2F;a&gt;,
which is the case in Europe) &lt;a href=&quot;#fr-airplane-mode-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-dump1090-forks&quot;&gt;
&lt;p&gt;It seems, from my understanding, that at some point in the
distant past, one fella made a program called &lt;code&gt;dump1090&lt;&#x2F;code&gt;. It seems like it
used to dump data via JSON or the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;firestuff&#x2F;adsb-tools&#x2F;blob&#x2F;master&#x2F;protocols&#x2F;beast.md&quot;&gt;Beast
protocol&lt;&#x2F;a&gt;,
which other tools could feed off of (such as
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;wiedehopf&#x2F;tar1090&quot;&gt;&lt;code&gt;tar1090&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;). Now, at some point,
the original tool seems to have been abandoned, and many people made their
own forks. One of them replaced JSON output with a protobuff output, and
others kept JSON and rewrote parts of the tool. I picked one of the
variants, by the folks behind FlightAware, which kept the JSON output. &lt;a href=&quot;#fr-dump1090-forks-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-tar1090&quot;&gt;
&lt;p&gt;&lt;code&gt;tar1090&lt;&#x2F;code&gt; seems cool, but the problem is that it is essentially a
collection of scripts and Nginx configs and PHP scripts that gets installed,
with a new created user, and so on and so on. It’s kind of a lot to ask for
just a software that shows me plane information on a map. &lt;a href=&quot;#fr-tar1090-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>My reading queue as of January 2025</title>
        <published>2025-01-21T00:00:00+00:00</published>
        <updated>2025-01-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/what-am-i-reading-january-2025/"/>
        <id>https://vulpinecitrus.info/blog/what-am-i-reading-january-2025/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/what-am-i-reading-january-2025/">&lt;p&gt;i wanted to write a little something about the books i am currently reading (as
of January 2025), both technical and fiction. Don’t expect a thorough review, i
generally haven’t made it past half of those. Some titles are in French, of
course, because i am afflicted with a rare condition called “being French”.
It’s terminal. Look it up online. Take some time to open a tab on
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.deepl.com&#x2F;en&#x2F;translator&quot;&gt;Deepl&lt;&#x2F;a&gt; as well.&lt;&#x2F;p&gt;
&lt;p&gt;Anyways, here it is.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;IPv6:_Théorie_et_Pratique&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#IPv6:_Théorie_et_Pratique&quot; aria-label=&quot;Anchor link for: IPv6:_Théorie_et_Pratique&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
IPv6: Théorie et Pratique&lt;&#x2F;h1&gt;
&lt;p&gt;by Gizèle Cizault (O’Reilly) &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;isbnsearch.org&#x2F;isbn&#x2F;9782841770854&quot;&gt;[9-782841-770854]&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This book essentially goes over all of the technical and theoretical aspects of
IPv6. It’s a technical book, unsurprisingly, so a lot of it for me so far feels
like a long list of various information about many aspects of the protocol.
Getting into this book is made much harder by the fact that i have the second
edition, which was published &lt;em&gt;in 1999&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Fun fact: Gizèle Cizault does not exist. It’s a pen name of the thirty or so
researchers and academics who contributed to the G6 work group that authored
the book, among other things. This happens more often than you’d think.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Compilers:_Principles,_Techniques_and_Tools&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Compilers:_Principles,_Techniques_and_Tools&quot; aria-label=&quot;Anchor link for: Compilers:_Principles,_Techniques_and_Tools&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Compilers: Principles, Techniques and Tools&lt;&#x2F;h1&gt;
&lt;p&gt;by Alfred V. Aho, Ravi Sethi and Jeffrey D. Ullman (Addison-Wesley Publishing Company) &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;isbnsearch.org&#x2F;isbn&#x2F;9780201100884&quot;&gt;[9-780201-100884]&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It’s the dragon book.&lt;&#x2F;p&gt;
&lt;p&gt;If you don’t know what the dragon book is, it’s essentially the reference for
every single (good) university class on compilers. At least the foundation. It
goes over everything from what constitutes a token, to how to build parsers, to
how to turn those into automata, and so on. Thing is, however, that the edition
i have was printed in 1985. Compiler research has &lt;em&gt;somewhat&lt;&#x2F;em&gt; evolved since then,
and the last edition, in the 2000s, does not go into great length into things
like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Polytope_model&quot;&gt;polyhedral compilers&lt;&#x2F;a&gt; or how
the rise of Symmetric MultiProcessor (SMP) and parallelism came into play in the
late 90s.&lt;&#x2F;p&gt;
&lt;p&gt;But it’s a good read. If you ever need a complete, thorough reference on the
basics of how to make a compilers, and don’t want to just open the LLVM codebase
and inflict yourself with man-made horrors beyond your comprehension.&lt;&#x2F;p&gt;
&lt;p&gt;Oh and it’s also ridiculously expensive because it’s technical &lt;em&gt;and&lt;&#x2F;em&gt; a class
requirement.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Réseaux&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Réseaux&quot; aria-label=&quot;Anchor link for: Réseaux&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Réseaux&lt;&#x2F;h1&gt;
&lt;p&gt;by Andrew Tanenbaum (3rd edition) (translated by Jean-Alain Hernandez &amp;amp; René Joy) (InterÉdition Paris) &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;isbnsearch.org&#x2F;isbn&#x2F;9782729606435&quot;&gt;[9-782729-606435]&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Another old technical french book, this one from the 80s. Andrew Tanenbaum, who
is kind of a big deal in the game of operating systems, essentially goes over
all of the technical aspects of networking from the standpoint of someone who,
in the 80s, might have had to use a computer to do technical things with it and
the network, but also implement new things.&lt;&#x2F;p&gt;
&lt;p&gt;That book usually sits on my desk at work, as it comes from the library of the
lab i work at. i go through it when i feel utter despair at the idea of doing
the actual things i get paid for. Kind of like the next book in this post.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Système_d’exploitation_(2nd_edition)&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Système_d’exploitation_(2nd_edition)&quot; aria-label=&quot;Anchor link for: Système_d’exploitation_(2nd_edition)&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Système d’exploitation (2nd edition)&lt;&#x2F;h1&gt;
&lt;p&gt;by Andrew Tanenbaum (translated by Jean-Luc Bourbon, Jean-Alain Hernandez &amp;amp; René Joly) (Pearsons Education France) &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;isbnsearch.org&#x2F;isbn&#x2F;9782744070020&quot;&gt;[9-782744-070020]&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Same deal as the previous book, except this is about operating systems in general.
A lot of the principles described in there are still somewhat applicable, and
some of those are still used in CS classes. This is not susprisingg considering
that CS education tends to only talk about UNIX-like monolithic operating system
kernels.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;House_of_Leaves&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#House_of_Leaves&quot; aria-label=&quot;Anchor link for: House_of_Leaves&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
House of Leaves&lt;&#x2F;h1&gt;
&lt;p&gt;by Mark Z. Danielewsky (2nd edition) (Pantheon Books) &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;isbnsearch.org&#x2F;isbn&#x2F;9780375703768&quot;&gt;[9-780375-703768]&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;span style=&quot;color: #6095f7;&quot;&gt;House&lt;&#x2F;span&gt;
 of Leaves is a book about darkness, and sound.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;span style=&quot;color: #6095f7;&quot;&gt;House&lt;&#x2F;span&gt;
 of leaves is a book about the life of a man that
gets ruined by his progressively deteriorating mental health, increasing
obsession with a delusional, gargantuous project, and the condition of the
world around him beating him down until he is a delirious, shallow shell of a
person.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;span style=&quot;color: #6095f7;&quot;&gt;House&lt;&#x2F;span&gt;
 of Leaves is a book by Zampanó, who dies before the
events of the book start taking place. In it, he captures the lives of people
who have been touched by a small compendium of several pieces of film, writing,
and interviews, detailing the story of the Navidson family, and, especially,
head of the family &lt;em&gt;William Navidson&lt;&#x2F;em&gt;. The Navidsons moved into a quiet little
&lt;span style=&quot;color: #6095f7;&quot;&gt;house&lt;&#x2F;span&gt;
 with the hope of being able to mend their
marriage that’s falling apart. That works, up until the family faces impossible
geometry in the &lt;span style=&quot;color: #6095f7;&quot;&gt;house&lt;&#x2F;span&gt;
 in the form of walls that keep
changing in length, alcoves and hallways suddenly appearing in the &lt;span style=&quot;color: #6095f7;&quot;&gt;house&lt;&#x2F;span&gt;
, and the &lt;span style=&quot;color: #6095f7;&quot;&gt;house&lt;&#x2F;span&gt;
 revealing a path into a
deep maze defying the physical world that swallows everything and everyone
living in the &lt;span style=&quot;color: #6095f7;&quot;&gt;house&lt;&#x2F;span&gt;
.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;span style=&quot;color: #6095f7;&quot;&gt;House&lt;&#x2F;span&gt;
 of Leaves is one of the last possessions held by
Will Navidson as he finds himself losing hope to escape the impossible darkness
underneath the &lt;span style=&quot;color: #6095f7;&quot;&gt;house&lt;&#x2F;span&gt;
. The other one is a box of matches.&lt;&#x2F;p&gt;
&lt;p&gt;I actually finished reading that book while this post was sitting in the queue,
but i still included it, because it is a fascinating piece of literature.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;The_King_in_Yellow&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#The_King_in_Yellow&quot; aria-label=&quot;Anchor link for: The_King_in_Yellow&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
The King in Yellow&lt;&#x2F;h1&gt;
&lt;p&gt;by Robert W. Chambers &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.gutenberg.org&#x2F;ebooks&#x2F;8492&quot;&gt;[Project Gutenberg]&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Another horror classic. A collection of short horror stories, and the most
famous one is the first one (the only one i have read so far).&lt;&#x2F;p&gt;
&lt;p&gt;Imagine this book, that when you read it, confers you with unspeakable horrors.
The narrator is unreliable, the story is just plain odd in the way that makes
the horror very subtle and diffused throughout the narration.&lt;&#x2F;p&gt;
&lt;p&gt;This book is more notoriously known these days for being featured in the 2022
hit videogame &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Signalis&quot;&gt;Signalis&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Rust_Atomics_&amp;amp;_Locks_(1st_edition)&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Rust_Atomics_&amp;amp;_Locks_(1st_edition)&quot; aria-label=&quot;Anchor link for: Rust_Atomics_&amp;amp;_Locks_(1st_edition)&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Rust Atomics &amp;amp; Locks (1st edition)&lt;&#x2F;h1&gt;
&lt;p&gt;by Mara Bos (O’Reilly Media) &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;isbnsearch.org&#x2F;isbn&#x2F;9781098119447&quot;&gt;[9-781098-119447]&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This book goes over all of the knowledge you need to handle parallelism and
especially locking in Rust. It is written by Mara Bos of the rust library team.
It does a very good job of introducing these problems from the start to people
who already know how to write some Rust. It starts with the fact that we have
threads that exist in the language, how to use them, and then &lt;em&gt;everything that
can go wrong when you try to manipulate data from multiple threads&lt;&#x2F;em&gt;, and
especially how to help that with locks. The rest of the book goes over how
these things are implemented, and guides you towards creating small toy
implementations of these locks.&lt;&#x2F;p&gt;
&lt;p&gt;Funnily enough, i started reading that book after coming back from Kernel
Recipes 2024, and had the pleasant surprise of discovering that i had lunch
there with the guy who wrote the foreword. Pretty neat fella who talked to me
about RCU.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Bullshit_Jobs&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Bullshit_Jobs&quot; aria-label=&quot;Anchor link for: Bullshit_Jobs&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Bullshit Jobs&lt;&#x2F;h1&gt;
&lt;p&gt;by David Graeber (Les Liens qui Réveillent) &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;isbnsearch.org&#x2F;isbn&#x2F;9791020907363&quot;&gt;[9-791020-907363]&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This book extends the thesis that Graeber first put out into the world in the
early 2010s: there are entire lines of work that are designed solely to keep the
workers busy doing things that are depressingly useless and that even they
cannot convince themselves are useful, &lt;em&gt;even though&lt;&#x2F;em&gt; they are required to keep
the outward appearance that they are. Graeber is an anthropologist, and it is
kind of fascinating for me to read a book written by an academic in such a
distinct domain of research. Human sciences bring themselves to such different
ways of presenting your thesis and the supporting evidence.&lt;&#x2F;p&gt;
&lt;p&gt;The book is essentially segmented as follows: what are bullshit jobs, what are
the archetypes of bullshit jobs, why having a bullshit job hurts, what is it
like to have a bullshit job, why do they keep proliferating, why is nobody
doing anything about it, and what can we do about that problem. My bookmark
tells me i’m somewhere between “what are the archetypes of bullshit jobs” and
“why does it hurt so much to have one”.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Des_Électeurs_Ordinaires:_Enquête_sur_la_normalisation_de_l’extrême_droite&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Des_Électeurs_Ordinaires:_Enquête_sur_la_normalisation_de_l’extrême_droite&quot; aria-label=&quot;Anchor link for: Des_Électeurs_Ordinaires:_Enquête_sur_la_normalisation_de_l’extrême_droite&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Des Électeurs Ordinaires: Enquête sur la normalisation de l’extrême droite&lt;&#x2F;h1&gt;
&lt;p&gt;by Félicien Faury (Seuil) &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;isbnsearch.org&#x2F;isbn&#x2F;9782021518948&quot;&gt;[9-782021-518948]&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This book is a sociological study of a sample of people who are in favour of the
French far-right party &lt;em&gt;Rassemblement National&lt;&#x2F;em&gt;. Most interestingly, the author
chose to study people in an area of France that is not usually talked about for
its high adherence to far-right ideologies. It is often thought that only former
industrial regions ravaged by globalization were in favour of the party.
Consequently, people only focused on these demographics repeat far-right
talking points linked to loss of job opportunities and stagnating paychecks,
somewhat justifying these ideas, which in reality are just masks used to mask
more nefarious policies, which they also often justify with the first talking
points (e.g. “migrants are stealing your jobs we should close the border”).&lt;&#x2F;p&gt;
&lt;p&gt;As Faury shows progressively in the book, what really drives adherence to the
RN in south-eastern France is not, in fact, just a fear of economic insecurity.
The general take-away of the book is that a culture of racism and lack of
diversity in the demographics, mixed with the feeling that people are not doing
as well as they should in the social hierarchy, leads them to need to &lt;em&gt;blame&lt;&#x2F;em&gt;
someone. These people look for a category of &lt;em&gt;others&lt;&#x2F;em&gt;, who are not them, who
they feel like they can get away with blaming for the failure of the system that
was rigged against all but the richest. Those people are often migrants, the
poor, the disabled, irrespective of whether or not the people studied actually
encounter them in their daily lives or not. The RN also points at migrants,
queers, the poor, the disabled, etc, and says “those are the people
responsible for the system not working how it should, who are stealing your job,
stealing your money, going against your values”. They promise to do something
about it, which is more than any liberal or right-wing government has in the
last 30 years or so, and that’s all that voters need to hear.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Converting raw IQ from `rtl_sdr` to WAV IQ for SDR++</title>
        <published>2024-12-30T00:00:00+00:00</published>
        <updated>2024-12-30T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/converting-raw-iq-rtl_sdr-wav-iq-sdrpp/"/>
        <id>https://vulpinecitrus.info/blog/converting-raw-iq-rtl_sdr-wav-iq-sdrpp/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/converting-raw-iq-rtl_sdr-wav-iq-sdrpp/">&lt;p&gt;Recently i published the first of a &lt;a href=&quot;&#x2F;tags&#x2F;radio%20listening&#x2F;&quot;&gt;series of posts on radio
listening&lt;&#x2F;a&gt;, and while this is not technically part 2
yet, i figured something out that is quite important to my workflow of
&lt;em&gt;recording&lt;&#x2F;em&gt; and then processing radio input.&lt;&#x2F;p&gt;
&lt;p&gt;i own a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.rtl-sdr.com&#x2F;v4&#x2F;&quot;&gt;RTL SDR Blog V4 dongle&lt;&#x2F;a&gt;, which is based on
the RTL2832U chip. The drivers you install come with a set of
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rtlsdrblog&#x2F;rtl-sdr&quot;&gt;binaries&lt;&#x2F;a&gt;, including &lt;code&gt;rtl_sdr&lt;&#x2F;code&gt;, which
lets you record a band of the spectrum into a raw data file. Later on, because i
use &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.sdrpp.org&#x2F;&quot;&gt;SDR++&lt;&#x2F;a&gt;, i would ideally want to open those files
and process them with the UI in that program. SDR++ (or &lt;code&gt;sdrpp&lt;&#x2F;code&gt;) is also capable
of recording raw bands of the spectrum into what it calls &lt;em&gt;baseband&lt;&#x2F;em&gt; files, but
it cannot immediately open raw files recorded from &lt;code&gt;rtl_sdr&lt;&#x2F;code&gt;. The reason for
that is that &lt;code&gt;rtl_sdr&lt;&#x2F;code&gt; outputs RAW “IQ” information, whereas &lt;code&gt;sdrpp&lt;&#x2F;code&gt; reads “IQ”
information in a WAV file.&lt;&#x2F;p&gt;
&lt;details&gt;
&lt;summary&gt;&lt;u&gt;&lt;i&gt;My (incorrect) understanding at the time of the technical aspects of IQ data&lt;&#x2F;u&gt;&lt;&#x2F;i&gt;, by me, an idiot&lt;&#x2F;summary&gt;
&lt;br&gt;
For reasons that are too complex (lol) to get into and that are also somewhat
starting to fade from my memory, an alternating electrical signal can be
expressed as a complex number: it has a magnitude, a period as a function of
time, and an initial shift. Complex numbers, represented in their more &quot;vector&quot;
or &quot;algebraic&quot; form are essentially two numbers in a trench coat: one is real
(let&#x27;s call it Q), and one is &quot;imaginary&quot; (let&#x27;s call it I). When reading from
the RTL2832U chip, you probably get two samples, 8 bit each, for I then Q. What
`rtl_sdr` does, roughly, after tuning, is reading a given number of those
samples and writing them in a file, which is then *RAW IQ* (as in, just wrote
the I and Q parts one after the other in a big sequence, no headers, no
nothing).
&lt;p&gt;What SDR++ and other tools will record and read, however, is &lt;em&gt;WAV IQ&lt;&#x2F;em&gt;, which is
to say, IQ data that has been de-interleaved, processed into the appropriate
number size for the program (SDR++ lets you choose, and GnuRadio &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;osmocom.org&#x2F;projects&#x2F;rtl-sdr&#x2F;wiki&#x2F;Rtl-sdr#Using-the-data&quot;&gt;uses 32-bit
floating point numbers&lt;&#x2F;a&gt;).
How exactly the signal is created remains somewhat of a mystery to me at this
point. My best guess is that the conversion process involves taking in the
decoded complex number from IQ data and generating the corresponding input
signal, and then mushing them all together. Exactly how that works? When i
figure it out, i will update this part.&lt;&#x2F;p&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;There is exactly one workflow where i would, ideally, not want to have to be on
the UI and click a button to record on SDR++ at a precise time and again to stop
it: satellite listening. Whether it be for catching SSTV from the ISS, LRPT from
the Russian Weather Satellites, i do not want to &lt;em&gt;get up at 7AM to do it&lt;&#x2F;em&gt;. Or,
rather, it is highly inconvenient that it’s always the ideal time. i also
recently discovered that, at least for SSTV from the ISS, a straight dipole is
often fine.&lt;&#x2F;p&gt;
&lt;p&gt;So how about slapping a bunch of &lt;code&gt;sleep&lt;&#x2F;code&gt; commands, a bit of CLI nonsense, and
get this recorded and opened in SDR++ later so i can actually record the track i
want? Well, reviewing the command i use for &lt;code&gt;rtl_sdr&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rtl_sdr -f 145.8e6 -s 60K -g 20 iq-145800000Hz.raw&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Summing up what is going on:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-f 145.8e6&lt;&#x2F;code&gt;: tune to 145.8MHz&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-s 60K&lt;&#x2F;code&gt;: record a bandwidth of &lt;em&gt;60K&lt;&#x2F;em&gt;. &lt;code&gt;rtl_sdr&lt;&#x2F;code&gt; uses the term “sample rate”
which is also used by SDR++; what it actually means is how many samples are
taken around the tuning frequency, or &lt;em&gt;how big&lt;&#x2F;em&gt; the band you’re seeing “at
once” is&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-g 20&lt;&#x2F;code&gt;: set the gain to 20 on the dongle&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;file name&amp;gt;&lt;&#x2F;code&gt;: pretty explicit; this one includes the frequency, for a reason
i will explain later&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Now, i use &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;chirlu&#x2F;sox&quot;&gt;&lt;code&gt;sox&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; to process the raw data into a WAV container:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sox -t raw -r 200k -b 8 -e unsigned-integer iq-145800000Hz.raw \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -t wav -r 200k -b 16 iq_145800000Hz.wav&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There is probably an equivalent for FFMPEG, but i haven’t tested that yet.&lt;&#x2F;p&gt;
&lt;p&gt;What it does is, roughly:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;There is an input from file &lt;code&gt;iq-145800000Hz.raw&lt;&#x2F;code&gt;:
&lt;ul&gt;
&lt;li&gt;The bit per sample (&lt;code&gt;-b&lt;&#x2F;code&gt;) is 8&lt;&#x2F;li&gt;
&lt;li&gt;There are &lt;code&gt;200k&lt;&#x2F;code&gt; samples per slice of input&lt;&#x2F;li&gt;
&lt;li&gt;The type is &lt;code&gt;raw&lt;&#x2F;code&gt; data&lt;&#x2F;li&gt;
&lt;li&gt;The integer type is &lt;code&gt;unsigned&lt;&#x2F;code&gt; (here for 8 bits: &lt;code&gt;0-255&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;The file created as an output, &lt;code&gt;iq-145800000Hz.wav&lt;&#x2F;code&gt; is:
&lt;ul&gt;
&lt;li&gt;Of type &lt;code&gt;wav&lt;&#x2F;code&gt;,&lt;&#x2F;li&gt;
&lt;li&gt;Has a sample rate of &lt;code&gt;200k&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;An integer type of &lt;code&gt;16&lt;&#x2F;code&gt; bits (you can change this part depending on what you
use in SDR++)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Now, opening the resulting file &lt;code&gt;iq_145800000Hz.wav&lt;&#x2F;code&gt; with SDR++ &lt;em&gt;should&lt;&#x2F;em&gt; show
you exactly the recording you plan to use.&lt;&#x2F;p&gt;
&lt;p&gt;And why the frequency in the file name? Well, see, SDR++ needs to know a center
frequency to show you on the tuner, and while it does not actually matter when
reading a file (the waterfall will just display the entire band and let you zoom
in on it and use other tuners like radio, NOAA, METEOR, etc. on parts of it), it
is good to now where you are tuned in if you have for example bookmarks and
such.&lt;&#x2F;p&gt;
&lt;p&gt;So how does SDR++ determine the center frequency from the WAV file? Easy, &lt;em&gt;&lt;strong&gt;the
fucking &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;AlexandreRouma&#x2F;SDRPlusPlus&#x2F;blob&#x2F;46bcba7594de0a8286d8d9e3a3633fb7b21abe38&#x2F;source_modules&#x2F;file_source&#x2F;src&#x2F;main.cpp#L183&quot;&gt;file name&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;i kid you not; i spent a solid 20 minutes digging in the code only to figure out
that &lt;code&gt;getFrequency&lt;&#x2F;code&gt; searches the filename with a regex to figure out the first
occurrence of &lt;code&gt;[0-9]+Hz&lt;&#x2F;code&gt;, and returns &lt;em&gt;0Hz&lt;&#x2F;em&gt; otherwise. That is actually a smart
choice considering the limitations of WAV files (i.e. you cannot use custom
labels for metadata and they are generally annoying to use in general).&lt;&#x2F;p&gt;
&lt;!--
vim: set cc=80 tw=80:
--&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Diving into Radio Listening: Introduction</title>
        <published>2024-12-19T00:00:00+00:00</published>
        <updated>2024-12-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/diving-into-rf/"/>
        <id>https://vulpinecitrus.info/blog/diving-into-rf/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/diving-into-rf/">&lt;p&gt;In the late 2000s, when i was a wee child, my parents brought me along to the
big yard sale organized in the tiny town my grandparents lived in. One
particular time, we came back with a set of electronic gizmos that included a
marine radio set. That huge cube of metal, with a deployable 2-meter long
antenna &lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-ft-1-1&quot;&gt;&lt;a href=&quot;#fn-ft-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, and a big selector to pick between various AM bands labeled
with lengths, CB, Maritime Frequencies, etc, also came with a booklet left there
by the previous owner with tables of names of foreign radios, and, in a big
grid, hour intervals. That radio set is probably collecting dust in a garage at
the moment, but it gave me a couple dozen hours of fun for the price of several
9V batteries.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Radio_Listening:_An_Introduction&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Radio_Listening:_An_Introduction&quot; aria-label=&quot;Anchor link for: Radio_Listening:_An_Introduction&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Radio Listening: An Introduction&lt;&#x2F;h1&gt;
&lt;p&gt;For most of my life, my only exposure to radio was via the commercial FM
stations my parents listened to throughout the day when i was a kid, and in the
car. i had several ideas in my mind about these elusive “radio waves”:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;radio waves are electromagnetic and you can’t feel them but they’re there, and
line of sight is important, but they can also bounce, somewhat; kind of like
visible light&lt;&#x2F;li&gt;
&lt;li&gt;radio waves were how TV and phone and WiFi worked, and sometimes you could be
in a spot where no signal could exist, and a meter next to there you’d have
great reception&lt;&#x2F;li&gt;
&lt;li&gt;radio was AM or FM, and those meant that the sound was transmitted
differently, although i had no idea how exactly&lt;&#x2F;li&gt;
&lt;li&gt;you could tune to a specific number to hear a different signal, and it worked&lt;&#x2F;li&gt;
&lt;li&gt;Signals could only travel so far, and different antennas in different regions
would emit the same station sometimes at different frequencies&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In August 2024 i &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.rtl-sdr.com&quot;&gt;bought&lt;&#x2F;a&gt; a &lt;abbr title=&quot;Software
Defined Radio&quot;&gt;SDR&lt;&#x2F;abbr&gt;. It’s not a particularly good one; the point was that
i wanted to explore radio frequency listening, something that had always
lingered in the back of my mind, and recently became a newfound topic of
interest within the French internet thanks to a
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=DPsEvzwtRY4&quot;&gt;couple&lt;&#x2F;a&gt;
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=YayiqGwKxJk&quot;&gt;videos&lt;&#x2F;a&gt; by a French creator and
musician.&lt;&#x2F;p&gt;
&lt;p&gt;and thus, i fell down the RF rabbit hole. This is sort of an introduction of a
series of posts that will come in the future. Those posts will be more
digestible little bites of exploration on specific topics, as opposed to the
first draft of a huge post i originally attempted on this topic. Things we
should cover, in no particular order:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Listening in on my local airport&lt;&#x2F;li&gt;
&lt;li&gt;Losing my mind at French RF regulation&lt;&#x2F;li&gt;
&lt;li&gt;Eaves-dropping on the neighborhood kids and the chilling experience of knowing
all you broadcast can be listened to&lt;&#x2F;li&gt;
&lt;li&gt;That time i cobbled together a little raspberry pi, my phone and my SDR to
listen to what everyone was saying downtown&lt;&#x2F;li&gt;
&lt;li&gt;France being a paranoid country so even firefighters use encrypted comms&lt;&#x2F;li&gt;
&lt;li&gt;That one time i received an industrial sensor alert via POCSAG (pagers) and
shit myself (conversely: that one time i received a message via POCSAG with
an exact address and someone’s cause of death)&lt;&#x2F;li&gt;
&lt;li&gt;Listening to an american pastor talk from thousands of kilometers away with a
puny little stick of metal&lt;&#x2F;li&gt;
&lt;li&gt;Soldering a bicycle brake wire to make the stupidest antenna in existence&lt;&#x2F;li&gt;
&lt;li&gt;Running across a parking lot with an antenna pointed at the night sky and
yelling “COME BACK HERE YOU FUCKING INTERNATIONAL SPACE STATION MY TAXES PAY
FOR YOU”&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;And much more.&lt;&#x2F;p&gt;
&lt;p&gt;Don’t expect necessarily 100%-accurate information either. i am armed with a
SDR, and a computer science engineering degree. i might try to get my telco
friends to check over this, and i can always pray to the
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;ia800501.us.archive.org&#x2F;30&#x2F;items&#x2F;AntennaTheoryAnalysisAndDesign3rdEd&#x2F;Antenna%20Theory%20Analysis%20and%20Design%203rd%20ed.pdf&quot;&gt;Balanis&lt;&#x2F;a&gt;
for guidance, but the science gets over my head when we reach the physical layer
of a medium. You can help me improve this by sending an email if you want.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;A_Primer_on_Electromagnetic_Frequencies_and_Their_Propagation&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#A_Primer_on_Electromagnetic_Frequencies_and_Their_Propagation&quot; aria-label=&quot;Anchor link for: A_Primer_on_Electromagnetic_Frequencies_and_Their_Propagation&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
A Primer on Electromagnetic Frequencies and Their Propagation&lt;&#x2F;h1&gt;
&lt;p&gt;Nonetheless, here is a primer on information that should be necessary to follow
along, but digestible. This section &lt;em&gt;might&lt;&#x2F;em&gt;  be updated as i add and correct
information for further posts in the series. If you are a physicist or work in
telco, plug your ears and close your eyes:&lt;&#x2F;p&gt;
&lt;p&gt;Electromagnetic wave propagate in space. The space around us is full of
electricity, or, rather, with the &lt;em&gt;potential&lt;&#x2F;em&gt; of electricity hanging around.
Analogous to that, the air around is is like a big space full of individual
points of air that can be more or less compressed locally. Like mechanical
waves, EM waves are created by a disturbance in the field through which they
propagate. The disturbance changes the property of the space, or milieu. For
air, a sudden push will locally compress air, which will then push against the
air nearby, and so on. For EM waves, the change in electrical potential will
propagate in space, creating a change in the field locally, which propagates.
The key property of waves is that they are a propagating disturbance that keeps
even after the source of the disturbance has ceased acting on the milieu.
Examples of that for sound waves are: your voice, or thunder. The sound of
thunder travels to you even as you’ve already seen the strike hit and fade away,
and the light of stars extinct for millions of years is still in the process of
reaching us.&lt;&#x2F;p&gt;
&lt;p&gt;When propagating, electromechanical waves diminish in intensity as they travel
and hit matter. The exact way they dissipate and how much they can traverse
before being fully imperceptible depends on other properties. For light, that
travel happens at a speed that physicist will ask you to consider to be
constant, because theories seem to uphold that (at least last time i did an
optics lab in university). The milieu of propagation actually impacts
propagation ever so slightly, creating effects such as rainbows and most
diffraction.&lt;&#x2F;p&gt;
&lt;p&gt;So far i’ve mostly talked about light, because it is the most intuitive form of
electromagnetic wave. However, they exist on a spectrum. Waves are typically
described by the “shape” they have: the way they modify the property of the
milieu as time goes on. That “shape” changes depending on the source of
the disturbance and potentially the shape of objects around (which is why a
piano sounds different from a guitar, or a trumpet). That shape may be very
uniform, as in the field of propagation (air, or the electromagnetic field)
changes at a constant rate and a constant period, in which case you have a
“pure” signal at &lt;em&gt;one&lt;&#x2F;em&gt; frequency: the interval of time it takes to return to a state of
the wave you have already seen (also called a period). If your period is 1&#x2F;440th
of a second long for sound, you hear a nice &lt;em&gt;A&lt;&#x2F;em&gt; note. For
electromagnetic waves, if you have exactly 530000 billion periods in a
second, you are seeing the color green. Because periods get ridiculously small,
we use &lt;em&gt;frequency&lt;&#x2F;em&gt;, the number of periods per second, with the “Hertz” unit. The
prior examples are usually expressed as 440Hz (A note) and 530 THz (Terahertz,
or 1000 billion hertz).&lt;&#x2F;p&gt;
&lt;p&gt;For electromagnetic waves we also tend to talk about the &lt;em&gt;wavelength&lt;&#x2F;em&gt; of a
signal. Because light travels at a constant speed, we can know precisely how far
it will have gone during one period at a given frequency. That length, the
length of a wave, is used to characterize a pure signal. Our 530 THz green has
a wavelength of about 565 nanometres. It means that if you placed precise
measurement tools every 565 nanometres for that specific wave of green, which
could extremely accurately measure the modification of the electric field, you
would see them all show the same value. They would keep the same value if you
slid them all alongside the direction of propagation.&lt;&#x2F;p&gt;
&lt;p&gt;Frequencies start at 0 (which is not technically possible on an alternating
signal like we are talking about so far). From 0 to about 10^10 Hertz (or
10GHz), we find radio waves. Those have a wave length varying from about as big
as possible (in most practical uses, at most the size of a skyscraper), all the
way to an insect. At 2.5GHz (12cm wavelength), you’ve got your microwave oven’s
frequency for bringing water to a boil, and old standards for WiFi. At around
5.1Ghz all the way to 5.7GHz (~5.5cm wavelength), you get your modern WiFi 5. In
general, we will be concerned with what happens between a couple hundreds of
kilohertz, and about 1.5GHz.&lt;&#x2F;p&gt;
&lt;p&gt;So far i have only talked about electromagnetic waves of a given pure frequency,
meaning that if you could visually observe the wave, you would see a change in
the electromagnetic field around you happening uniformly, with the field going
“up” for half the period, then “down” for the rest of the period, following a
sine pattern, which would repeat forever. In reality, things are messy. As
mentioned, not everything is a pure signal of one frequency, in fact, it would
be highly impractical. So we do better.&lt;&#x2F;p&gt;
&lt;p&gt;In the 1810s, a guy by the name of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Joseph_Fourier&quot;&gt;Jean-Baptiste Joseph Fourier&lt;&#x2F;a&gt; (yes, he is french, sorry), was interested in modeling how heat propagates
in materials (he helped launch a little field of physics called thermodynamics,
nothing big). After settling in the french city of Grenoble, he worked at the
theory and figured that heat propagates between two objects based on the
difference in temperature they show. As part of his work on the matter, Fourier
actually developed a nice property that we still use to this day: under certain
circumstances, a seemingly chaotic function can be broken down into a
(potentially infinite) sum of decreasingly big sine waves. For the less
mathematically inclined, this means that if you take any form of wave in the
right circumstances (and in physics we can assume those for any wave), we can
break that seemingly chaotic variation of the field into a set of variations of
one frequency with different proportions, or what i’ve been calling for now
“pure signals”, i.e. sine waves.&lt;&#x2F;p&gt;
&lt;p&gt;In space, when a piece of equipment puts out a disturbance of the EM field, it
can be decomposed as modifications of precise frequencies through an operation
called the &lt;em&gt;Fourier transform&lt;&#x2F;em&gt;, where we take the input signal and break it down
into individual frequencies and how much they are being affected. When two
signals collide in space, these base components add to each other. In some
circumstances, this means that one signal will cancel out the other: if two
signals of exactly the same pure frequency, but slightly shifted in time,
collide, the sum of modifications to the propagation milieu will be null: there
will be no signal. In sound, this is the technology behind &lt;em&gt;active noise
cancelling&lt;&#x2F;em&gt; (where the headphones play an inverted recording of your
environment’s noise to subtract the noise from the signal your ears receive). In
other circumstances, two signals can collide and amplify one another.&lt;&#x2F;p&gt;
&lt;p&gt;So, back to electromagnetic waves, we want to encode some sort of information
into electromagnetic waves. Having Fourier transforms, which our computers and
analog electronics can do reasonably well, is doable. In fact, electronics are
actually really good, when given AC voltage at the right frequency, and with the
correct components, at creating an alternating current that can have a precise
frequency and intensity. If, by chance, that alternating current is going down
through a piece of conductive material, the change in motion of the electricity
through the wire will create a &lt;em&gt;magnetic wave&lt;&#x2F;em&gt; around the wire. If that change
keeps repeating, the magnetic wave (which at that point will have also created
changes in the electric field, meaning that the wave is both electronic and
magnetic) will start alternating at exactly the frequency, or frequencies we
want. This is, roughly, radio emission. The converse operation happens when a
piece of metal is present and influenced by a change in its surrounding
electromagnetic field, creating tiny changes in current in the wire, which can
be picked up by precise components down the line, and interpreted as reception
of an electromagnetic wave: that’s reception, with an antenna.&lt;&#x2F;p&gt;
&lt;p&gt;To receive radio waves, i use a software defined radio, or &lt;em&gt;SDR&lt;&#x2F;em&gt;. Typical radios
you will find are meant to be used on commercial bands, where voice is broadcast
either via the (wideband) FM or AM modes. Your radio will shift some properties
of its analog (or digital) components (a bit of resistance here, a bit of
capacitance there), and suddenly it is attuned to changes at a particular
frequency, and those nearby. In a software defined radio, my computer is the one
telling the SDR what it needs to attune to. The SDR is made up of three important
components: an antenna to pick up a signal (i actually plug it into the dongle,
but that’s irrelevant because it’s necessary anyways), a decoder chip that
interprets the incoming electrical noise as signals, and a tuner that changes
parameters of the decoder chip to target a certain range of reception
frequencies.&lt;&#x2F;p&gt;
&lt;p&gt;Encoding information into an electromagnetic signal usually follows one of two
methods: &lt;em&gt;amplitude modulation&lt;&#x2F;em&gt; or &lt;em&gt;frequency modulation&lt;&#x2F;em&gt;. In reality, many
others exist, but i will focus on voice for now, which, unless you are using a
digital transmission system, uses of those two. Your voice, and whatever else
music is mixed with it, is an analog signal that can typically vary up to about
20 KHz (the range the human ear can pick up). In order to encode the
information, the emitter picks a frequency, called the &lt;em&gt;carrier&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In amplitude modulation (AM), the analog signal is used to change the
&lt;em&gt;amplitude&lt;&#x2F;em&gt; of the carrier. Imagine your nice sine wave, repeating at the
frequency of the carrier that you’ve picked (e.g. 100 KHz), except the sine does
not go up to 1 or -1 every time. The contour of the sine draws the shape of the
much lower frequency signal that you want to express:&lt;&#x2F;p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;commons.wikimedia.org&#x2F;wiki&#x2F;File:Amfm3-en-de.gif#&#x2F;media&#x2F;File:Amfm3-en-de.gif&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;upload.wikimedia.org&#x2F;wikipedia&#x2F;commons&#x2F;a&#x2F;a4&#x2F;Amfm3-en-de.gif&quot; alt=&quot;Animation of audio, AM and FM modulated carriers.&quot; height=&quot;200&quot; width=&quot;256&quot;&gt;&lt;&#x2F;a&gt;&lt;br&gt;By &lt;a href=&quot;https:&#x2F;&#x2F;ru.wikipedia.org&#x2F;wiki&#x2F;User:Berserkerus&quot; class=&quot;extiw&quot; title=&quot;ru:User:Berserkerus&quot;&gt;Berserkerus&lt;&#x2F;a&gt; - &lt;span class=&quot;int-own-work&quot; lang=&quot;en&quot;&gt;Own work&lt;&#x2F;span&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;creativecommons.org&#x2F;licenses&#x2F;by-sa&#x2F;2.5&quot; title=&quot;Creative Commons Attribution-Share Alike 2.5&quot;&gt;CC BY-SA 2.5&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;commons.wikimedia.org&#x2F;w&#x2F;index.php?curid=5071748&quot;&gt;Link&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;In frequency modulation, you take the variation of the input signal to change
the frequency of the carrier. That is, if your signal is a nice sine wave like
shown above, your FM signal will alternately have a slightly higher frequency
than its carrier, then a slightly lower frequency. The effect of this is that
your signal, once processed to decompose it into its pure components via a
Fourier transform, will exhibit a peak that oscillates around the frequency of
the carrier. To simplify, AM draws the signal on the amplitude you measure,
whereas FM draws the signal on the Fourier decomposition.&lt;&#x2F;p&gt;
&lt;p&gt;This is why you typically need to capture a &lt;em&gt;range&lt;&#x2F;em&gt; of frequencies around the
carrier. Information is actually encoded in a given range of frequencies. Even
for amplitude modulation, where we multiply the carrier and the signal, the
resulting signal is actually a sum of sines that are around the frequency of the
carrier. In fact, for the AM mode, the range that these frequencies can
take is twice the range of frequencies of the input signal. For FM, it is
the same as the input signal. That range of frequency that is listened to to
demodulate your signal is called the &lt;em&gt;bandwidth&lt;&#x2F;em&gt; of the signal.&lt;&#x2F;p&gt;
&lt;p&gt;The typical way you will show the presence of electromagnetic waves and how they
break down into individual frequencies is called a &lt;em&gt;spectrogram&lt;&#x2F;em&gt;, it will show
the &lt;em&gt;spectrum&lt;&#x2F;em&gt; of frequencies that you are interested in. A very specific type
of spectrogram is often used by radio software, is called the &lt;em&gt;waterfall
spectrogram&lt;&#x2F;em&gt;. An example is shown below:&lt;&#x2F;p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;commons.wikimedia.org&#x2F;wiki&#x2F;File:SDRpp_FM_subcarriers.png#&#x2F;media&#x2F;File:SDRpp_FM_subcarriers.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;upload.wikimedia.org&#x2F;wikipedia&#x2F;commons&#x2F;0&#x2F;0e&#x2F;SDRpp_FM_subcarriers.png&quot; alt=&quot;SDRpp FM subcarriers.png&quot; height=&quot;847&quot; width=&quot;733&quot;&gt;&lt;&#x2F;a&gt;&lt;br&gt;By &lt;a href=&quot;&#x2F;&#x2F;commons.wikimedia.org&#x2F;w&#x2F;index.php?title=User:Konung_yaropolk&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;User:Konung yaropolk (page does not exist)&quot;&gt;Konung yaropolk&lt;&#x2F;a&gt; - &lt;span class=&quot;int-own-work&quot; lang=&quot;en&quot;&gt;Own work&lt;&#x2F;span&gt;, &lt;a href=&quot;http:&#x2F;&#x2F;creativecommons.org&#x2F;publicdomain&#x2F;zero&#x2F;1.0&#x2F;deed.en&quot; title=&quot;Creative Commons Zero, Public Domain Dedication&quot;&gt;CC0&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;commons.wikimedia.org&#x2F;w&#x2F;index.php?curid=129068196&quot;&gt;Link&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In waterfall displays of a spectrum, a gradient of colors (here blue to dark
red) encodes how &lt;em&gt;intense&lt;&#x2F;em&gt; the received frequency is, which is its amplitude.
Recall that a signal diminishes in intensity, or amplitude, the weaker it gets.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;Conclusion&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Conclusion&quot; aria-label=&quot;Anchor link for: Conclusion&quot;&gt;#&lt;&#x2F;a&gt;&amp;nbsp;
Conclusion&lt;&#x2F;h1&gt;
&lt;p&gt;So, this is about as much as i can cram into a single article, and about as much
as i can explain before we get into other stuff that can be explained in another
article. This section is absolutely getting updated at some point, but we’ll
see.&lt;&#x2F;p&gt;
&lt;p&gt;See you by the spectrum waterfall~&lt;&#x2F;p&gt;
&lt;!-- vim: set cc=80 tw=80: --&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-ft-1&quot;&gt;
&lt;p&gt;or at least it felt that long when i was like, 8. &lt;a href=&quot;#fr-ft-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>A 2024 Update on the Rust Foxes Linux Module</title>
        <published>2024-08-20T00:00:00+00:00</published>
        <updated>2024-08-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/news-of-the-rust-foxes-module/"/>
        <id>https://vulpinecitrus.info/blog/news-of-the-rust-foxes-module/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/news-of-the-rust-foxes-module/">&lt;p&gt;First, the context.&lt;&#x2F;p&gt;
&lt;p&gt;For those who are not aware, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;rust-for-linux.com&#x2F;&quot;&gt;Rust for Linux&lt;&#x2F;a&gt; is a project within the Linux
developer community to add kernel support for the Rust programming language with
the objective of developing drivers that can sit alongside regular C drivers in
tree. The project is still somewhat young, but it’s already reached the
significant milestone of a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;netdev&#x2F;net-next.git&#x2F;commit&#x2F;?id=d6beb085e8ff3d9547df8a5a55f15ccc7552c5d0&quot;&gt;first driver being merged&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Two years ago i came across Rust for Linux thank to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;c&#x2F;AsahiLina&quot;&gt;Asahi Lina&lt;&#x2F;a&gt;’s
M1 GPU driver development streams. i went through a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.jackos.io&#x2F;rust-kernel&#x2F;rust-for-linux.html&quot;&gt;quick
tutorial&lt;&#x2F;a&gt;, and &lt;em&gt;voilà&lt;&#x2F;em&gt;, there was a driver:
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;alopexlemoni&#x2F;rust-foxes-module&quot;&gt;&lt;code&gt;rust_foxes&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Two_Years_Later&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Two_Years_Later&quot; aria-label=&quot;Anchor link for: Two_Years_Later&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Two Years Later&lt;&#x2F;h2&gt;
&lt;p&gt;Now, two years later almost, what has changed?&lt;&#x2F;p&gt;
&lt;p&gt;First, the Rust for Linux project deprecated the &lt;code&gt;rust&lt;&#x2F;code&gt; branch everyone used to
experiment. It was full of abstractions for many, many things (including
miscellaneous devices, user IO, etc), but its development had not followed the
regular process of (painstakingly) posting things on the LKMLs, and people
reviewing them.&lt;&#x2F;p&gt;
&lt;p&gt;So almost everything was basically thrown into the trash. What is coming now is
definitely an opportunity to do better (eg. properly handling multiple memory
allocators, properly defining memory allocation flags, a better structure for
the &lt;code&gt;alloc&lt;&#x2F;code&gt; crate, etc).&lt;&#x2F;p&gt;
&lt;p&gt;That also means that the driver no longer really works unless you build against
the old &lt;code&gt;rust&lt;&#x2F;code&gt; branch from back in the days of 6.0… Well it would have, if i
had rebased my code. Even the API for simple modules changed between me writing
the module, and when &lt;code&gt;rust&lt;&#x2F;code&gt; was abandoned.&lt;&#x2F;p&gt;
&lt;p&gt;For example, consider &lt;code&gt;Module::init&lt;&#x2F;code&gt;, the entrypoint of a module. In my code it
is:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; init&lt;&#x2F;span&gt;&lt;span&gt;(_name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;static CStr&lt;&#x2F;span&gt;&lt;span&gt;, _module&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;static ThisModule&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Result&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;Self&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The current definition used in both &lt;code&gt;rust&lt;&#x2F;code&gt; and &lt;code&gt;rust-next&lt;&#x2F;code&gt; (the up-to-date
branch used to push RFL’s updates to Linus):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; init&lt;&#x2F;span&gt;&lt;span&gt;(_module&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;static ThisModule&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Result&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;Self&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Thankfully, during the last two years, i have spent a big part of my time
working on drivers using RFL’s tree, including making abstractions.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Update_Time&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Update_Time&quot; aria-label=&quot;Anchor link for: Update_Time&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Update Time&lt;&#x2F;h2&gt;
&lt;p&gt;Going through the code, as someone who now has 2 more years of experience not
only writing drivers for RFL but also, crucially, abstractions, i listed several
things in need of update:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;Module&lt;&#x2F;code&gt; trait&lt;&#x2F;li&gt;
&lt;li&gt;Missing &lt;code&gt;miscdev&lt;&#x2F;code&gt; abstractions&lt;&#x2F;li&gt;
&lt;li&gt;Missing &lt;code&gt;io_buffer&lt;&#x2F;code&gt; abstractions&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;For the missing abstractions, i dove in the code of the old &lt;code&gt;rust&lt;&#x2F;code&gt; branch and
pulled out the big chunks of code my driver had previously relied on. Then, i
brushed up very little details to update the code.&lt;&#x2F;p&gt;
&lt;p&gt;As an example, consider code that turns a &lt;code&gt;Result&lt;&#x2F;code&gt; into an errno code. RFL’s
&lt;code&gt;rust&lt;&#x2F;code&gt; had a macro for that purpose, which is now replaced by
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Rust-for-Linux&#x2F;linux&#x2F;blob&#x2F;7bc186731e87482662c4f86da455f435fe838fb6&#x2F;rust&#x2F;kernel&#x2F;error.rs#L320&quot;&gt;&lt;code&gt;kernel::error::from_result&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In a similar fashion, everything that allocates now needs specific memory
allocation flags to be passed so that the proper call is made and &lt;code&gt;gfp&lt;&#x2F;code&gt; is not
always assumed.&lt;&#x2F;p&gt;
&lt;p&gt;i trimmed the code down to the minimum needed to open and read the device:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Abstractions for &lt;code&gt;struct file_operations&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Abstractions to copy and write from userland&lt;&#x2F;li&gt;
&lt;li&gt;Abstractions for IO buffers&lt;&#x2F;li&gt;
&lt;li&gt;Abstractions for simple devices&lt;&#x2F;li&gt;
&lt;li&gt;Abstractions to register a &lt;code&gt;miscdevice&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The set of changes totals &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;Lymkwi&#x2F;linux&#x2F;commit&#x2F;19494f77f9de852a177302ea432d5866a212107c&quot;&gt;+1240
lines&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Now,_onto_the_driver&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Now,_onto_the_driver&quot; aria-label=&quot;Anchor link for: Now,_onto_the_driver&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
Now, onto the driver&lt;&#x2F;h3&gt;
&lt;p&gt;After fixing imports and the problem of &lt;code&gt;Module&lt;&#x2F;code&gt; trait implementation, i decided
to flex a little by adding a new feature to the driver.&lt;&#x2F;p&gt;
&lt;p&gt;Previously, the driver would mindlessly write foxes one after the other, &lt;em&gt;ad
infinitum&lt;&#x2F;em&gt;. That was funny, but i can do better.&lt;&#x2F;p&gt;
&lt;p&gt;The trait for file operations has two associated types. One of these types
represents a data type passed to the handler of the &lt;code&gt;open()&lt;&#x2F;code&gt; event. The precise
instance is stored in memory when we request the registration:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; reg&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; miscdev&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Options&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;mode&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;0o444&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;register_new&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;kernel&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;fmt!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;foxes&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;), ())&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this example, and in my current version of the driver, that type is &lt;code&gt;()&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;A second associated type tells the file operations what type is passed for all
callbacks within the same &lt;code&gt;open&#x2F;release&lt;&#x2F;code&gt; session. That is, the instance is
created during the &lt;code&gt;open&lt;&#x2F;code&gt; callback, and destroyed at &lt;code&gt;release&lt;&#x2F;code&gt;. A borrowed
version of the data is then passed for all callbacks… including &lt;code&gt;read&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;read&lt;&#x2F;code&gt; callback is the only one i implement, and the only one i need.
Ironically, i use it to write in the buffer the user provided. Previously, that
writing filled the buffer given by the user as much as possible, including with
&lt;em&gt;partial foxes&lt;&#x2F;em&gt; (first few bytes of an incomplete UTF-8 emoji). Now, with the
session data type set to &lt;code&gt;Box&amp;lt;AtomicUsize&amp;gt;&lt;&#x2F;code&gt;, i obtained a &lt;code&gt;&amp;amp;AtomicUsize&lt;&#x2F;code&gt; on all
callbacks, and could now play with it.&lt;&#x2F;p&gt;
&lt;p&gt;Importantly, all core atomic scalar types can be modified through a non-mutable
reference. That was all i was going to get anyways:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[vtable]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;impl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Operations&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; for&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; FoxDev&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Box&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;AtomicUsize&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; open&lt;&#x2F;span&gt;&lt;span&gt;(_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;(), _file&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;File&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Result&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;Self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Data&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        Ok&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Box&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;AtomicUsize&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;200&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; GFP_KERNEL&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; read&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;AtomicUsize&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        _file&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;File&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        writer&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;: &amp;amp;mut impl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; IoBufferWriter&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        offset&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; u64&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    )&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Result&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        &#x2F;&#x2F;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The really simple part was changing the writing code so that it checks the
current count remaining, limits itself to that value (or not if the buffer is
small), and then subtracts the number of foxes fully written. Once the count is
exhausted, and a round of &lt;code&gt;read&lt;&#x2F;code&gt; returns 0 bytes read, your program will likely
call &lt;code&gt;close()&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;With that code in place, all calls to &lt;code&gt;cat &#x2F;dev&#x2F;foxes&lt;&#x2F;code&gt;, for example, will show
the same number of foxes before exiting.&lt;&#x2F;p&gt;
&lt;p&gt;In a subsequent modification (one i have not pushed to the repository), i even
made it so the count became global to all different reading attempts. In order
to do that, i wrapped a &lt;code&gt;AtomicUsize&lt;&#x2F;code&gt; in an &lt;code&gt;Arc&lt;&#x2F;code&gt; (Atomic Referenced Counter),
and used that as a data type for the &lt;code&gt;open&lt;&#x2F;code&gt; callback, at which point i cloned
the &lt;code&gt;Arc&lt;&#x2F;code&gt; and used it for all callbacks as well. The count was decreased in a
similar way, except this time it was global to multiple parallel calls.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Conclusion&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Conclusion&quot; aria-label=&quot;Anchor link for: Conclusion&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;i underwent this little restoration project as an attempt to not lose my mind
writing a more complex, fully-fledged driver for RFL. The cute little character
device that prints foxes is a cute example and the first example of code i used
in the project, so i would like it to remain up-to-date, and useful to people
who want to get into the project.&lt;&#x2F;p&gt;
&lt;p&gt;Reflecting quickly on my (almost) two years of practice, i realized that while i
gained a certain amount of skepticism regarding the capacity of the project to
onboard newcomers to the kernel (myself included), i gained a lot of knowledge
of how Linux works internally, but also how FFI in Rust interacts with it, and
how deep primitives like cells, tools like &lt;code&gt;Arc&lt;&#x2F;code&gt; or &lt;code&gt;Box&lt;&#x2F;code&gt;, and regular code can
work together. It’s been a journey, and while i hope to take a break from more
serious endeavors around RFL, i will definitely keep tinkering.&lt;&#x2F;p&gt;
&lt;!--
vim: set cc=80 tw=80 spell spelllang=en:
--&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Irregular Reminder: Strip your Kernel Modules on Install</title>
        <published>2024-05-16T00:00:00+00:00</published>
        <updated>2025-02-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/irregular-reminder-kernel-install-mod-strip/"/>
        <id>https://vulpinecitrus.info/blog/irregular-reminder-kernel-install-mod-strip/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/irregular-reminder-kernel-install-mod-strip/">&lt;p&gt;Occasionally, I have to re-install a kernel and its modules. Worse, I have to do
it on Ubuntu (for reasons outside my control). I learned to do that on my own
mostly through a mixture of old Gentoo tutorials and kernel documentation.&lt;&#x2F;p&gt;
&lt;p&gt;And yet, twice already I have done the whole procedure, which, once your
configuration is done, and after you’ve &lt;em&gt;enabled kernel debugging&lt;&#x2F;em&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-kern-devel-1&quot;&gt;&lt;a href=&quot;#fn-kern-devel&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;,
is something akin to:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;make&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -j4&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; bzImage modules&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # i have four cores&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; make INSTALL_MOD_PATH=&#x2F;usr modules_install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; make INSTALL_HDR_PATH=&#x2F;usr headers_install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; cp arch&#x2F;x86&#x2F;boot&#x2F;bzImage &#x2F;boot&#x2F;vmlinuz-myversion&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; update-initramfs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -k&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; myversion&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -c -v&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and then: kaboom. My &lt;code&gt;initrd-myversion&lt;&#x2F;code&gt; is something like 1.2 gigabytes on disk
(if like me you are compiling the &lt;code&gt;x86_64-defconfig&lt;&#x2F;code&gt; profile with minimal
changes).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Yikes.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I know from experience that your bootloader is likely not going to love having
such a huge file to load. Kernel install blunder once: shame on me. Kernel
install blunder twice: let’s write about it.&lt;&#x2F;p&gt;
&lt;p&gt;The first time it happened to me, I spent about twenty minutes figuring out that
symbols were enabled, and clogged up the initramfs size.&lt;&#x2F;p&gt;
&lt;p&gt;I ended up also finding out that Linux’s industrial Rube Goldberg machine of a
Makefile architecture can &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;askubuntu.com&#x2F;questions&#x2F;1292683&#x2F;ubuntu-20-04-lts-after-building-custom-kernel-boot-freezes-at-loading-initial-r&#x2F;1333823#1333823&quot;&gt;read from another environment
variable&lt;&#x2F;a&gt;
called
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.kernel.org&#x2F;doc&#x2F;html&#x2F;v6.9&#x2F;kbuild&#x2F;kbuild.html#install-mod-strip&quot;&gt;&lt;code&gt;INSTALL_MOD_STRIP&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.
When the value in that variable is &lt;code&gt;1&lt;&#x2F;code&gt;, modules are stripped at install,
removing the symbols.&lt;&#x2F;p&gt;
&lt;p&gt;I ended up building a new initramfs, at 99 megabytes of size. Interestingly
enough, I have never had such an issue on ArchLinux using &lt;code&gt;mkinitcpio&lt;&#x2F;code&gt;. My
theory is that it either never pulls &lt;em&gt;all&lt;&#x2F;em&gt; of the modules into initramfs (very
likely true from my knowledge so far), or strips them, or both.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;&#x2F;strong&gt;: Use &lt;code&gt;INSTALL_MOD_STRIP=1&lt;&#x2F;code&gt; on &lt;code&gt;make modules_install&lt;&#x2F;code&gt; to reduce initramfs
size:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;make&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -j4&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; bzImage modules&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; # i have four cores&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; make INSTALL_MOD_PATH=&#x2F;usr INSTALL_MOD_STRIP=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; modules_install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; make INSTALL_HDR_PATH=&#x2F;usr headers_install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; cp arch&#x2F;x86&#x2F;boot&#x2F;bzImage &#x2F;boot&#x2F;vmlinuz-myversion&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; update-initramfs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -k&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; myversion&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -c -v&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;!--
vim: set spell spelllang=en tw=80 cc=80:
--&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-kern-devel&quot;&gt;
&lt;p&gt;i do kernel development, so i need symbols in core, but not in
&lt;em&gt;most&lt;&#x2F;em&gt; modules. &lt;a href=&quot;#fr-kern-devel-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Pushing to an Overleaf project through Forgejo</title>
        <published>2024-04-17T00:00:00+00:00</published>
        <updated>2024-04-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/git-forgejo-overleaf-sync/"/>
        <id>https://vulpinecitrus.info/blog/git-forgejo-overleaf-sync/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/git-forgejo-overleaf-sync/">&lt;p&gt;I am a PhD student. Of course, I write papers. For various reasons, my
supervisors and I use &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.overleaf.com&#x2F;&quot;&gt;Overleaf&lt;&#x2F;a&gt;, which is
satisfactory in terms of UX and such.&lt;&#x2F;p&gt;
&lt;p&gt;However, outside of periods with high editing contention, I would rather work
with my usual workflow of editing LaTeX with &lt;code&gt;neovim&lt;&#x2F;code&gt;, which I have customized
to compile and lint LaTeX code for me. I find writing lengthy pieces of text
more relaxing in a terminal. 🤷&lt;&#x2F;p&gt;
&lt;p&gt;Overleaf has a synchronization feature over &lt;code&gt;git&lt;&#x2F;code&gt;. You can choose to have your
project synchronized over a GitHub project, a DropBox, or anything that uses
&lt;code&gt;git&lt;&#x2F;code&gt;. For multiple reasons, I avoid the first two.&lt;&#x2F;p&gt;
&lt;p&gt;If you go to the project menu (with the leaf symbol, on the top left), select
“Git” in the “Sync” options, you will be presented with a URL like below, and
something about “&lt;em&gt;Git authentication token&lt;&#x2F;em&gt;”:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;https:&#x2F;&#x2F;git@git.overleaf.com&#x2F;&amp;lt;long string of numbers&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;The_Problem_with_Overleaf’s_Git_Tokens&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#The_Problem_with_Overleaf’s_Git_Tokens&quot; aria-label=&quot;Anchor link for: The_Problem_with_Overleaf’s_Git_Tokens&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
The Problem with Overleaf’s Git Tokens&lt;&#x2F;h2&gt;
&lt;p&gt;Git Authentication Tokens are generated in your &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.overleaf.com&#x2F;user&#x2F;settings&quot;&gt;user
settings&lt;&#x2F;a&gt; in the “Project
Synchronization” section under “Git Integration”. They are shown once, kind of
like most tokens. Creating one with “Add another token” leaves you with a long
string that starts with something like &lt;code&gt;olp_7d....&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Using passwords over &lt;code&gt;git&lt;&#x2F;code&gt; is generally a hassle, but Overleaf gives you no
other choice. Of course, not content with that prospect, I poked around and
played with my &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;&quot;&gt;Git Forge&lt;&#x2F;a&gt; to try and see if I
could create a workaround.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Working_Around_Password_Auth:_Forgejo_Push_Mirrors&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Working_Around_Password_Auth:_Forgejo_Push_Mirrors&quot; aria-label=&quot;Anchor link for: Working_Around_Password_Auth:_Forgejo_Push_Mirrors&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Working Around Password Auth: Forgejo Push Mirrors&lt;&#x2F;h2&gt;
&lt;p&gt;The goal: work on my paper like any regular Git repository.&lt;&#x2F;p&gt;
&lt;p&gt;To get to that goal, I want to be able to push to a remote that I have
configured in my &lt;code&gt;.ssh&#x2F;config&lt;&#x2F;code&gt;. My own forge is configured already, so I decided
to use it.&lt;&#x2F;p&gt;
&lt;p&gt;I created a &lt;em&gt;private&lt;&#x2F;em&gt; repository for my paper, and added it as a remote of the
local clone I had made of the work already done (so I had to &lt;code&gt;git-clone&lt;&#x2F;code&gt; once
with the HTTPS URL and token). Then, I went into “Settings” for that repository,
and under “Mirror Settings”, I added a new push mirror. Its URL is the HTTPS URL
shown by Overleaf, and in the “Authorization” section, I set the username to
&lt;code&gt;git&lt;&#x2F;code&gt;, and the password to the token. I enabled “Sync when commits are pushed”,
of course, and &lt;em&gt;voilà&lt;&#x2F;em&gt;!&lt;&#x2F;p&gt;
&lt;p&gt;Essentially, this uses your forge as a proxy to store your token, so you may
want to create one specifically for it. You can lower the mirror sync interval
for finer granularity of updates if you plan on never pulling from the Overleaf
repository. However, no matter how low you set the time, you will lag behind
anyone who is using Overleaf to edit the files there. Furthermore, if a conflict
arises, I am not exactly sure how Forgejo handles it. If I find out, I will
update this.&lt;&#x2F;p&gt;
&lt;!--
vim: set tw=80 cc=80 spell spelllang=en:
--&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Conky may be Leaking your RAM on ArchLinux</title>
        <published>2023-12-12T00:00:00+00:00</published>
        <updated>2023-12-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/archlinux-conky-memory-leak/"/>
        <id>https://vulpinecitrus.info/blog/archlinux-conky-memory-leak/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/archlinux-conky-memory-leak/">&lt;p&gt;Some time in the summer this year I started noticing that memory usage would
become very high after a while. Specifically, XOrg would start hogging inane
amounts of memory.&lt;&#x2F;p&gt;
&lt;p&gt;I use an NVidia GTX2070S card on my desktop computer (which uses the &lt;code&gt;x86_64&lt;&#x2F;code&gt;
architecture), so I just lazily think to myself “well NVidia is at it again” and
think not of it again.&lt;&#x2F;p&gt;
&lt;p&gt;Recently, after becoming irate with XOrg crashing in the middle of games, or
losing my open programs (and having to open 10 terminals again), I decided to
look into the source.&lt;&#x2F;p&gt;
&lt;p&gt;The estimated rate of leak was about 1 Megabyte per 10 seconds with nothing
launched but my basic desktop utilities, which include:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;polybar&#x2F;polybar&quot;&gt;&lt;code&gt;polybar&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; (which I often kill for
fullscreen gameplay, so it can’t be it)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;feh.finalrewind.org&#x2F;&quot;&gt;&lt;code&gt;feh&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; in a bash script that runs it every 20
minutes for a new desktop background&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;brndnmtthws&#x2F;conky&quot;&gt;&lt;code&gt;conky&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; which gives me fancy stats I
can’t see most of the ti- wait a second&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So immediately I restart my X session, kill &lt;code&gt;conky&lt;&#x2F;code&gt; and it stops leaking. An
hour passes and only a single megabyte gets allocated.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_Conky_Repository&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#The_Conky_Repository&quot; aria-label=&quot;Anchor link for: The_Conky_Repository&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
The Conky Repository&lt;&#x2F;h2&gt;
&lt;p&gt;I use vanilla Conky on Arch, aka. &lt;code&gt;extra&#x2F;conky&lt;&#x2F;code&gt;. It is developed over at
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;brndnmtthws&#x2F;conky&#x2F;&quot;&gt;&lt;code&gt;github.com&#x2F;brndnmtthws&#x2F;conky&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Searching for &lt;code&gt;is:issue memory Xorg&lt;&#x2F;code&gt; on the repository leads to issue
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;brndnmtthws&#x2F;conky&#x2F;issues&#x2F;1442&quot;&gt;#1442&lt;&#x2F;a&gt;, which details high
CPU and memory usage following a regression after introducing the use of new
colour data types for X11.&lt;&#x2F;p&gt;
&lt;p&gt;As it turns out, the pixel color data was being allocated, but not cached, and
kept being allocated again and again.&lt;&#x2F;p&gt;
&lt;p&gt;Well, darn.&lt;&#x2F;p&gt;
&lt;p&gt;The faulty commit,
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;brndnmtthws&#x2F;conky&#x2F;commit&#x2F;5e98c49c4c943b162b7a86e076f1b5479e4e640c&quot;&gt;&lt;code&gt;5e98c49&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;,
was introduced on February 24th 2023, and released into &lt;code&gt;v1.18.1&lt;&#x2F;code&gt; the same day.&lt;&#x2F;p&gt;
&lt;p&gt;The fix, commit &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;brndnmtthws&#x2F;conky&#x2F;pull&#x2F;1444&#x2F;commits&#x2F;c08a78208b7b2c4e1eb8288bc1c6e8a773b9f167&quot;&gt;&lt;code&gt;c08a782&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;brndnmtthws&#x2F;conky&#x2F;commit&#x2F;8f0a21bcc07ae6ab81b9aaf1e8f2ded1625da2be&quot;&gt;&lt;code&gt;8f0a21b&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
in the repository, fixes the issue, and was shipped in &lt;code&gt;1.18.2&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;So… it was fixed in March? Why’s it still broken?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_Conky_ArchLinux_Package&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#The_Conky_ArchLinux_Package&quot; aria-label=&quot;Anchor link for: The_Conky_ArchLinux_Package&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
The Conky ArchLinux Package&lt;&#x2F;h2&gt;
&lt;p&gt;As of writing this, ArchLinux ships version &lt;code&gt;1.18.1-2&lt;&#x2F;code&gt; of Conky, which I know is
faulty.&lt;&#x2F;p&gt;
&lt;p&gt;The package is apparently &lt;em&gt;marked as deprecated&lt;&#x2F;em&gt;, and has been since 2023-03-04,
the day &lt;code&gt;1.18.2&lt;&#x2F;code&gt; was released and the leak fixed. Yet, Conky on ArchLinux was
updated on 2023-09-03.. What’s up?&lt;&#x2F;p&gt;
&lt;p&gt;Packaging versions do not follow the same naming standards as software release.
Conky 1.18.1 was first released for ArchLinux on
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gitlab.archlinux.org&#x2F;archlinux&#x2F;packaging&#x2F;packages&#x2F;conky&#x2F;-&#x2F;commit&#x2F;dce6d73f13b76ce48fe395f7adb61cf7a5bff1cd&quot;&gt;February 24th 2023&lt;&#x2F;a&gt;
as &lt;code&gt;1.18.1-1&lt;&#x2F;code&gt; by Levente Polyak, maintainer of the package.&lt;&#x2F;p&gt;
&lt;p&gt;On &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gitlab.archlinux.org&#x2F;archlinux&#x2F;packaging&#x2F;packages&#x2F;conky&#x2F;-&#x2F;commit&#x2F;293d79cbcf6a7abb05dcd8f9227505b70b227a6e&quot;&gt;September 19th
2023&lt;&#x2F;a&gt;
they released &lt;code&gt;1.18.1-2&lt;&#x2F;code&gt;… Which essentially just locked the build to a tag,
specified some SPDX license identifiers, and enabled Wayland.&lt;&#x2F;p&gt;
&lt;p&gt;And that’s it. No pulling the new version (by then, Conky &lt;code&gt;v1.19.4&lt;&#x2F;code&gt; had been
released upstream for a month).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;So…?&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#So…?&quot; aria-label=&quot;Anchor link for: So…?&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
So…?&lt;&#x2F;h2&gt;
&lt;p&gt;There’s not much to take away from this. Packaging is done by people. People are
busy. Sometimes packages are stuck. We are stuck with this Conky leaking huge
amounts of RAM for now… I might update this if I find more things, or when it
gets solved.&lt;&#x2F;p&gt;
&lt;p&gt;Hopefully if you had the same problem, and you were as lazy as I was to diagnose
it, now you know why.&lt;&#x2F;p&gt;
&lt;!--
vim: set spell tw=80 cc=80:
--&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Using git with email: a Quick Tutorial</title>
        <published>2023-12-03T00:00:00+00:00</published>
        <updated>2023-12-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/git-send-email-quick-tutorial/"/>
        <id>https://vulpinecitrus.info/blog/git-send-email-quick-tutorial/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/git-send-email-quick-tutorial/">&lt;p&gt;I am mostly writing this as a self memo for how to use &lt;code&gt;git-send-email&lt;&#x2F;code&gt;, and by
extension &lt;code&gt;git-format-patch&lt;&#x2F;code&gt; and &lt;code&gt;git-am&lt;&#x2F;code&gt;, to share patches, patchsets, and
apply them.&lt;&#x2F;p&gt;
&lt;p&gt;Me and my friends like to do these overly elaborate things to share code, what
we jokingly call “fossbro roleplaying”, so hopefully it can help them, and you
as well!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;“Wait_what’s_all_that_about?”&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#“Wait_what’s_all_that_about?”&quot; aria-label=&quot;Anchor link for: “Wait_what’s_all_that_about?”&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
“Wait what’s all that about?”&lt;&#x2F;h2&gt;
&lt;p&gt;These commands let you create patches that represent a commit (with all of its
metadata, save for cryptographic signature), share them automatically over
email, and, once someone downloads the contents of your email, apply those
commits to a tree.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Preliminary_Settings&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Preliminary_Settings&quot; aria-label=&quot;Anchor link for: Preliminary_Settings&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Preliminary Settings&lt;&#x2F;h2&gt;
&lt;p&gt;TL;DR: These are the settings you want to tweak. Mine would be:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --global&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; sendemail.smtpencryption tls&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --global&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; sendemail.smtpserver smtp.vulpinecitrus.info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --global&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; sendemail.smtpuser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;use&lt;&#x2F;span&gt;&lt;span&gt;r&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --global&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; sendemail.smtpserverport&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 587&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; config&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --global&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; sendemail.from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;my emai&lt;&#x2F;span&gt;&lt;span&gt;l&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These settings replace CLI parameters you can otherwise provide when sending
email with &lt;code&gt;git send-email&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Exporting_with_format-patch&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Exporting_with_format-patch&quot; aria-label=&quot;Anchor link for: Exporting_with_format-patch&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Exporting with format-patch&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;code&gt;git-format-patch&lt;&#x2F;code&gt; commands turns a commit or set of commits into files that
can be straightforwardly sent as email.&lt;&#x2F;p&gt;
&lt;p&gt;The only real positional argument provides the range or set of commits to
format. That can be quite hard to wrap your head around but here’s a quick
rundown:&lt;&#x2F;p&gt;
&lt;div style=&quot;overflow-x: auto;&quot;&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Argument&lt;&#x2F;th&gt;&lt;th&gt;Meaning&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;lt;ref&amp;gt;&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;All commits from &lt;code&gt;&amp;lt;ref&amp;gt;&lt;&#x2F;code&gt; to &lt;code&gt;HEAD&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;A..B&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;All commits in the range from A (excluded) to B (included)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-n&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Last &lt;code&gt;n&lt;&#x2F;code&gt; commits from &lt;code&gt;HEAD&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Note that because &lt;code&gt;git&lt;&#x2F;code&gt; is the way it is, and because, when you think about it,
it makes sense: when your range includes a divergence, you might pull all of the
divergent commit from it. It’s just how &lt;code&gt;git&lt;&#x2F;code&gt; works. In the end, you will get
all the commits you need, but they will be linearized, so the application order
might be a bit wonky or cause merge errors.&lt;&#x2F;p&gt;
&lt;p&gt;Everything else is just optional arguments. Here are those I think would
be the most useful:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--rfc&lt;&#x2F;code&gt;: your patch or patchset is a request for comments&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-v &amp;lt;n&amp;gt;&lt;&#x2F;code&gt;: mark this as version &lt;code&gt;&amp;lt;n&amp;gt;&lt;&#x2F;code&gt; of your patchset&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;--cover-letter&lt;&#x2F;code&gt;: generate a file that represents the cover letter, or the
big description you send to explain the whole point of your patchset; by
default it contains diff stats, and such&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;--thread=&amp;lt;style&amp;gt;&lt;&#x2F;code&gt;: the thread style controls how your commits follow each
other. A &lt;code&gt;shallow&lt;&#x2F;code&gt; style means all subsequent email are a reply to the
first one (typically the cover letter). That is the standard on LKLMs.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;--in-reply-to=&amp;lt;message-id&amp;gt;&lt;&#x2F;code&gt;: oddly enough, I have already had to send a
patch as a reply to a human-made series of email. This may be useful for
that purpose.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;Sending_with_send-email&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Sending_with_send-email&quot; aria-label=&quot;Anchor link for: Sending_with_send-email&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Sending with send-email&lt;&#x2F;h2&gt;
&lt;p&gt;This is the big complex part. Technically, &lt;code&gt;git-send-email&lt;&#x2F;code&gt; is a big Perl script
that wraps around calls to your mail sender. As such, you may find some missing
dependencies such as &lt;code&gt;perl-authen-sasl&lt;&#x2F;code&gt; on Arch Linux.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;send-email&lt;&#x2F;code&gt; command takes your files and sends them as email. Easy. Except
it does a lot of things for you and is very fuzzy in terms of available options.
For example, it takes all emails from the &lt;code&gt;Signed-off-by:&lt;&#x2F;code&gt; and such lines in
your commits, and adds them as &lt;code&gt;Cc:&lt;&#x2F;code&gt; lines in the email sent unless you tell it
not to.&lt;&#x2F;p&gt;
&lt;p&gt;Here are the options I generally use:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--to=&amp;lt;email&amp;gt;&lt;&#x2F;code&gt;: a new &lt;code&gt;To:&lt;&#x2F;code&gt; line&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;--cc=&lt;&#x2F;code&gt;: a new &lt;code&gt;Cc:&lt;&#x2F;code&gt; line&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;--bcc=&lt;&#x2F;code&gt;: a new &lt;code&gt;Bcc:&lt;&#x2F;code&gt; line&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;--compose&lt;&#x2F;code&gt;: if you did not generate and edit a cover letter, write it now&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;--no-signed-off-by-cc&lt;&#x2F;code&gt;: this removes the automated gathering of emails in
the &lt;code&gt;Signed-off-by:&lt;&#x2F;code&gt; lines to &lt;code&gt;Cc:&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;--suppress-cc=&amp;lt;choice&amp;gt;&lt;&#x2F;code&gt;: suppress automatically found &lt;code&gt;Cc:&lt;&#x2F;code&gt;, you can see the
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;docs&#x2F;git-send-email&quot;&gt;man page&lt;&#x2F;a&gt; for all choices&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;--dry-run&lt;&#x2F;code&gt;: do everything but send the actual email; the information sent to
the SMTP server is shown in the standard output for debugging purposes&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;There is actually an interesting overlap between &lt;code&gt;send-email&lt;&#x2F;code&gt; and
&lt;code&gt;format-patch&lt;&#x2F;code&gt;. You can actually configure most of everything you want for the
content of your email messages via either command, depending on your choice. For
example, had I not chosen threading style in &lt;code&gt;format-patch&lt;&#x2F;code&gt;, I could have
specified it in &lt;code&gt;send-email&lt;&#x2F;code&gt; using &lt;code&gt;--[no-]chain-reply-to&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Applying_with_am&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Applying_with_am&quot; aria-label=&quot;Anchor link for: Applying_with_am&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Applying with am&lt;&#x2F;h2&gt;
&lt;p&gt;If you find yourself the (un?)fortunate recipient of a patchset that you fancy
adding to your project, you can simply download your email to files (or,
honestly, just copy the visible content from your email browser), and run
&lt;code&gt;git am&lt;&#x2F;code&gt; on them. Ideally, you want to apply them &lt;em&gt;in order&lt;&#x2F;em&gt;, and over the
correct commit. The details for how to coordinate with your collaborators for
that to happen is left at your own discretion.&lt;&#x2F;p&gt;
&lt;p&gt;Interestingly, you can use &lt;code&gt;-S&lt;&#x2F;code&gt; with &lt;code&gt;am&lt;&#x2F;code&gt; to sign the objects created. The
signature from the original committer in their own repository cannot be
maintained, because &lt;em&gt;you&lt;&#x2F;em&gt; create the actual binary &lt;code&gt;git&lt;&#x2F;code&gt; objects tied to that
commit in the actual repository yourself, so &lt;em&gt;you&lt;&#x2F;em&gt; must sign and certify that
the content you create that commit with is valid. You are the first person
liable if something wrong is introduced (and others are on the line if there are
&lt;code&gt;Signed-off-by:&lt;&#x2F;code&gt; lines).&lt;&#x2F;p&gt;
&lt;p&gt;As as interesting side note, many places will let you download &lt;code&gt;.patch&lt;&#x2F;code&gt; files
that have the correct format to be an email and a &lt;code&gt;git&lt;&#x2F;code&gt; patch. For example:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;GitHub lets you do so for individual commits by adding &lt;code&gt;.patch&lt;&#x2F;code&gt; at the end of
the URL, and similarly with pull requests (except the patch contains all
individual patches for the PR’s commits)&lt;&#x2F;li&gt;
&lt;li&gt;GitLab does the exact same thing for both commits and merge requests&lt;&#x2F;li&gt;
&lt;li&gt;Gitea&#x2F;Forgejo also lets you do the same on both commits and PRs&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;As a result, you will often find yourself using &lt;code&gt;git am&lt;&#x2F;code&gt; on things that are not
purely email.&lt;&#x2F;p&gt;
&lt;p&gt;As an addendum, I can point you to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;flusp.ime.usp.br&#x2F;git&#x2F;sending-patches-by-email-with-git&#x2F;&quot;&gt;another
tutorial&lt;&#x2F;a&gt; by
Matheus Tavares.&lt;&#x2F;p&gt;
&lt;!--
vim: set spell:
vim: set tw=80:
--&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>VulpineCitrus is Changing CMS (Again)</title>
        <published>2023-11-06T00:00:00+00:00</published>
        <updated>2023-11-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/vulpinecitrus-is-changing-cms-again/"/>
        <id>https://vulpinecitrus.info/blog/vulpinecitrus-is-changing-cms-again/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/vulpinecitrus-is-changing-cms-again/">&lt;p&gt;&lt;em&gt;So, it has come to this again, uh?&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Last year, in 2022, &lt;a href=&quot;&#x2F;blog&#x2F;vulpinecitrus-is-changing-cms&quot;&gt;I moved my blog&lt;&#x2F;a&gt; from
Hexo, an old CMS tool written in NodeJS, to Grav, a self proclaimed minimalist
flat-file CMS. At the time, I had tinkered with Grav a bit, and came to be
confident that I could make something cool out of it.&lt;&#x2F;p&gt;
&lt;p&gt;For about a year or so, I did. However, as time went on, I realized two (well,
three) things about my actual workflow while writing blog posts.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Number_1:_I_do_not_actually_use_a_browser_that_often&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Number_1:_I_do_not_actually_use_a_browser_that_often&quot; aria-label=&quot;Anchor link for: Number_1:_I_do_not_actually_use_a_browser_that_often&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Number 1: I do not actually use a browser that often&lt;&#x2F;h2&gt;
&lt;p&gt;I started using Grav with the premise that I wanted to move away from having
scattered pieces of repositories on multiple computers, describing different
versions of drafts of posts. I wanted a tool that I could just open on any
computer, and start writing.&lt;&#x2F;p&gt;
&lt;p&gt;The problem with that premise is that:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;I actually use the same couple machines for writing, which I almost always
configure to have credentials to my git forge, and the right GPG keys to sign
commits with&lt;&#x2F;li&gt;
&lt;li&gt;Opening a browser is a hassle at times&lt;&#x2F;li&gt;
&lt;li&gt;Assets still stay scattered (for example, on my SNCF blog post, I had to wait
to get home multiple times to fetch screenshots)&lt;&#x2F;li&gt;
&lt;li&gt;Now that I am in a much more stable living situation, I have solid and
resilient infrastructure to synchronize code (my &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&quot;&gt;forge&lt;&#x2F;a&gt;,
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;cloud.vulpinecitrus.info&quot;&gt;Nextcloud&lt;&#x2F;a&gt;), meaning that out-of-sync code is not a problem&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;Number_2:_Grav_is_actually_quite_a_lot_of_work&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Number_2:_Grav_is_actually_quite_a_lot_of_work&quot; aria-label=&quot;Anchor link for: Number_2:_Grav_is_actually_quite_a_lot_of_work&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Number 2: Grav is actually quite a lot of work&lt;&#x2F;h2&gt;
&lt;p&gt;I had to do a non-insignificant amount of testing to place my posts in the order I wanted,
right off the bat. At first I ignored it, and after a while things just stayed in the right
order, but it was a first taste of things to come.&lt;&#x2F;p&gt;
&lt;p&gt;A lot of things work out of the box, thankfully, and I think Grav would be best
suited to someone who wants a more… simple and fancy solution.&lt;&#x2F;p&gt;
&lt;p&gt;I want high levels of customization and control, and I increasingly found myself
having to dig into raw Markdown files on Grav just to achieve things as simple
as excluding draft posts from feeds.&lt;&#x2F;p&gt;
&lt;p&gt;In the end, one last point pushed me back to the old philosophy that had me use
Hexo in the first place…&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Number_3:_Static_sites_are_resilient&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Number_3:_Static_sites_are_resilient&quot; aria-label=&quot;Anchor link for: Number_3:_Static_sites_are_resilient&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Number 3: Static sites are resilient&lt;&#x2F;h2&gt;
&lt;p&gt;About a month ago, I read a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;octodon.social&#x2F;@cwebber&#x2F;111263813133092819&quot;&gt;post&lt;&#x2F;a&gt;
on my timeline relating this weird phenomenon in web preservation… The late Aaron
Swartz (assasinated by the copyright industry; may he rest in peace) relating on
his blog at the time the unfortunate passing of Gene Kan, one of the pioneering
authors of the Gnutella file transfer protocol. At the time, Aaron noted that
Gene’s blog was barely preserved, and only static pages previously preserved could be
accessed. Yet, the way we can read Aaron’s words to this day is because he himself
used a static site generator, something that could construct pure static files
that were unlikely to break in the event that nobody were to deploy a new version
ever again. His blog is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.aaronsw.com&#x2F;weblog&#x2F;&quot;&gt;still online&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I have known my fair share of websites, old forums from the 2000s and 2010s,
completely broken and inaccessible. I have helped &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;InsaLan&#x2F;infra-insalan.fr&quot;&gt;rescue&lt;&#x2F;a&gt;
one of those for a school club that was absolutely falling apart. Nothing is
forever, but non-static websites are shifting sand, and you take a notable risk
in depending on them.&lt;&#x2F;p&gt;
&lt;p&gt;Now of course I am not some grey muzzle contemplating the looming threat of death,
but I am about Aaron’s age when he died, and I cannot help but think that, perhaps,
the simplest solutions to my problems are also the most likely to age better.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;A_new_adopted_CMS:_Zola&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#A_new_adopted_CMS:_Zola&quot; aria-label=&quot;Anchor link for: A_new_adopted_CMS:_Zola&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
A new adopted CMS: Zola&lt;&#x2F;h2&gt;
&lt;p&gt;I dabbled a bit with static site generators, first Hugo, then Zola. My affinity
for Rust (and unstable projects!) made me pick the latter.&lt;&#x2F;p&gt;
&lt;p&gt;It’s jank in a way that I appreciate, where it forces me to write templates myself
(I based my template on the Tilde template, but heavily customized for just about
all pages). That fits my workflow of putting time into things that I can
customize and dissect fully, to an extent where I have now written most of the raw
HTML code in this very page’s template, and can debug it if needed.&lt;&#x2F;p&gt;
&lt;p&gt;Zola, as a static site generator, is cool in the way that I can now rely on my
infrastructure to automatically deploy a new version once someone commits into
my repository… which is neat! Automation is good and actually fits into my
workflow as well.&lt;&#x2F;p&gt;
&lt;p&gt;So, we will see how things go. I will just keep on doing my silly littles things,
and you can keep on reading them.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;oh but actually&lt;&#x2F;strong&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Using Zola introduced a couple of changes:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;For breaking changes, the only thing I could not fix fully were RSS feed URLs.
I added a redirection rule in my reverse proxy to redirect the old paths, but
I encourage you, potential reader of this stream, to change your URLs now&lt;&#x2F;li&gt;
&lt;li&gt;I have an &lt;a href=&quot;&#x2F;me&quot;&gt;about me&lt;&#x2F;a&gt; page now. It’s quite barren, but I think it gets
through the major important points.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;That’s it, see you around the web!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Against Real Name Policies</title>
        <published>2023-10-12T00:00:00+00:00</published>
        <updated>2023-10-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/against-real-name-policies/"/>
        <id>https://vulpinecitrus.info/blog/against-real-name-policies/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/against-real-name-policies/">&lt;p&gt;You may be more used to reading things related to technology on this website, and you might be thinking to yourself “well this ain’t it, chief”.&lt;&#x2F;p&gt;
&lt;p&gt;You’re wrong.&lt;&#x2F;p&gt;
&lt;p&gt;There have been recent &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;peoplemaking.games&#x2F;@eniko&#x2F;111217385971291927&quot;&gt;discussions&lt;&#x2F;a&gt; in my online circles around the concept of “real-name policies”, which is a requirement within certain projects to provide your actual, real, legal, certified-100%-you name alongside your contribution. More generally, it is a requirement that people appear as a legally bound and identifiable identity within certain spaces and for certain purposes.&lt;&#x2F;p&gt;
&lt;p&gt;It might make sense to you at first if you have never thought about it any further of course: sure, sometimes you need to be able to delegate legal responsibilities to a contributor to your project, especially when it comes to their work and contribution. By then, &lt;em&gt;of course&lt;&#x2F;em&gt;, you think, naively, you need to have a &lt;em&gt;unique immutable legal certified gold-plated absolute name recognized by a state&lt;&#x2F;em&gt; to refer to them.&lt;&#x2F;p&gt;
&lt;p&gt;Can you sense I am exaggerating for a purpose?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Real_Names_do_Not_Exist&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Real_Names_do_Not_Exist&quot; aria-label=&quot;Anchor link for: Real_Names_do_Not_Exist&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Real Names do Not Exist&lt;&#x2F;h2&gt;
&lt;p&gt;As many people have pointed out, real names are just a fantasy. This might come as a shock to you, especially if your life revolves around using your name around for various purpose such as academic publication, contributions, administrative presentation, and such. Spoiler: your name is not any more real.&lt;&#x2F;p&gt;
&lt;p&gt;It may happen that, if you happen to travel abroad, your name will be transliterated on your passport. Which one is real then, the name recognized by X embassy, or that of your country of origin? Country of origin? Okay, but then what if within that state, agencies cannot even &lt;em&gt;agree&lt;&#x2F;em&gt; on how to spell it? Even my own government has made multiple mistakes in registering various people I know at their birth… And what if you do not have a country of origin, or no paper from that place? Say you’ve been uprooted by war, famine, climate change? Records have been destroyed?&lt;&#x2F;p&gt;
&lt;p&gt;People believe a lot of things about names. It’s like a lot of things. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.kalzumeus.com&#x2F;2010&#x2F;06&#x2F;17&#x2F;falsehoods-programmers-believe-about-names&#x2F;&quot;&gt;We believe falsehoods about names that do not pass the reality check&lt;&#x2F;a&gt; (that post is from &lt;strong&gt;13 years ago&lt;&#x2F;strong&gt;), and people in computer science are especially bad in that regard.&lt;&#x2F;p&gt;
&lt;p&gt;Now let’s introduce this: I have multiple names. People who know me as a silly fox online call me one thing, people who know me more personally online call me another, my friends IRL call me one of two names alternatively, my colleagues call me a third combination of first and last name, and the government might soon start to call me a fourth one if they aren’t &lt;em&gt;a-holes&lt;&#x2F;em&gt; about me asking them to. As a bonus fact, that is an especially complex situation to resolve when managing GPG keys, for example.&lt;&#x2F;p&gt;
&lt;p&gt;In this situation, none of these names are in any way less “real” than others. Nor should any of them be recognized as any more important and true than any other. They’re all real, in a way, all destined to their individual community, and if your answer to that is to say “okay, but then what’s on your ID”, well, we’ve reached the real hard problem with “real-name policies”:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Real-name policies drive away minorities whose “real name” is controversial or debatable in the eyes of the established norm&lt;&#x2F;strong&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If your policy requires that I reveal the male name I was given at birth, I will simply stop contributing to your project. I will also tell my other trans and non-binary friends that your project is not safe for them. From a utilitarian standpoint, I’d argue you will lose out on the contribution of very capable people. From a more general viewpoint, you contribute to a general climate of hostility and gatekeeping that alienates marginalized communities from your projects, meaning the same demographics of western cisgender (often men &amp;amp; white) people keep the helm of projects that could all benefit from diverse input.&lt;&#x2F;p&gt;
&lt;p&gt;And beyond people who change name because of a profound experience of self realization, those whose “real-name” is controversial will often be racial minorities, migrants, and such. They will also be caught in this.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;So?&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#So?&quot; aria-label=&quot;Anchor link for: So?&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
So?&lt;&#x2F;h2&gt;
&lt;p&gt;I’m the kind of person who thinks there shouldn’t even be such a concept as legal name. Legality is a collection of meaningless decorum we act through to keep up the collective hallucination of our society. That’s confusing enough of a take as is, but you can read between the lines to try and gather what it means.&lt;&#x2F;p&gt;
&lt;p&gt;In short? Don’t require people to disclose their “real” name when contributing to projects, whatever you think that means. Let people use nicknames, change names. Heck, let them &lt;em&gt;edit&lt;&#x2F;em&gt; their names in previous contributions as well (I have notable gripes about the way tools like &lt;strong&gt;git&lt;&#x2F;strong&gt;(1) handle names as a permanent record; once again, a tool which design could have benefited from input from other people; and it’s not the only one).&lt;&#x2F;p&gt;
&lt;p&gt;Here’s a couple of issues I think people could have:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;“But what if they submit something illegal” then you take the hit. Copyright issue? My answer is “fuck copyright”, but a more practical one for you would be: have people handle those issues and remove offending things if needed. Malicious code? Same. It doesn’t scale? Find a way to make it so that you don’t need people to disclose their deadnames or argue with you for hours about their IDs&lt;&#x2F;li&gt;
&lt;li&gt;“But what if they act maliciously as a result? Doesn’t anonymity foster antisocial behavior?” wow there’s a lot to unpack there, but in short: people are going to stick to a name that’s recognizable (heck, they might even have a little piece of government-issued plastic with that actual name on it!), such that they are going to build a reputation just the same way they would on social media or, very likely, in your organization chats. Yet, sometimes, that name could change. Or it could be used only in your social circles. Or maybe not! Identities are complex, and it blows my mind to recall that most people just have not grasped that fact, or never had to.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So, yeah, fuck real name policies, in short.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The SNCF WiFi API and All of its Funny Things</title>
        <published>2023-10-12T00:00:00+00:00</published>
        <updated>2025-09-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/the-sncf-wifi-api/"/>
        <id>https://vulpinecitrus.info/blog/the-sncf-wifi-api/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/the-sncf-wifi-api/">&lt;p&gt;Recently I had the unfortunate displeasure of having to move my vacation dates because of a &lt;em&gt;certain pandemic&lt;&#x2F;em&gt; that, despite the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.santepubliquefrance.fr&#x2F;dossiers&#x2F;coronavirus-covid-19&#x2F;coronavirus-chiffres-cles-et-evolution-de-la-covid-19-en-france-et-dans-le-monde&quot;&gt;silence of our health authorities&lt;&#x2F;a&gt;, is still ongoing and impacting people.&lt;&#x2F;p&gt;
&lt;p&gt;So instead of taking a crammed bus without ventilation for nine hours, my roommates and I got last minute tickets on the french high-speed railroad train: the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;TGV&quot;&gt;&lt;em&gt;Train à Grande Vitesse&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; (High-Speed Train).&lt;&#x2F;p&gt;
&lt;p&gt;Last time I took that train I realized there was something funny that I could play with in the train: its internet connection.&lt;&#x2F;p&gt;
&lt;!--Of course, I could *maybe* scan the entire network and discover users were all put in a `&#x2F;21` for the sake of isolation, but I was more interested with *whatever the heck the WiFi gave me*.--&gt;
&lt;h2 id=&quot;The_WiFi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#The_WiFi&quot; aria-label=&quot;Anchor link for: The_WiFi&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
The WiFi&lt;&#x2F;h2&gt;
&lt;p&gt;If you are on a TGV that has WiFi you gain access to what the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;sncf.fr&#x2F;&quot;&gt;Société Nationale des Chemins de fers Français (SNCF)&lt;&#x2F;a&gt; calls “WiFi SNCF”, which is essentially an on-board WiFi service. The SNCF engineered a system of repeaters that allow their trains to maintain a (somewhat) constant connection to a cellular data-like network. It mostly works. Of course, even they recognize and advertise that if you plan to use it for very bandwidth-intensive operations that need a fairly reliable connection, you should just wait. That serves them as well, to be honest, because they have to manage an internal network of many devices all going through a fairly tiny gateway. On my first train that day, we reached more than 240 devices connected in the train.&lt;&#x2F;p&gt;
&lt;p&gt;How do I know that? I did not learn that from a ping scan. The WiFi API told me.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Funny_Endpoints&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Funny_Endpoints&quot; aria-label=&quot;Anchor link for: Funny_Endpoints&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Funny Endpoints&lt;&#x2F;h2&gt;
&lt;p&gt;I already knew that there were web API endpoints you could call on the local user-friendly dashboard to the WiFi, accessible on every train at &lt;code&gt;wifi.sncf&lt;&#x2F;code&gt;. Me and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;borale.si&quot;&gt;a friend&lt;&#x2F;a&gt; planned on trying to inspect as many of them as possible during that trip (to kill time however we could).&lt;&#x2F;p&gt;
&lt;p&gt;Booting up developer tools on our web browsers, we noticed more than a handful of little queries that returned nice-looking JSON-encoded objects, and we dug deeper. What we found was:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Trip details and updates&lt;&#x2F;li&gt;
&lt;li&gt;WiFi metrics&lt;&#x2F;li&gt;
&lt;li&gt;Information used on the dashboard trip map&lt;&#x2F;li&gt;
&lt;li&gt;GPS position and heading&lt;&#x2F;li&gt;
&lt;li&gt;Various media&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So I’m going to go through them from least interesting to most interesting.&lt;&#x2F;p&gt;
&lt;p&gt;The full list of endpoints is:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&#x2F;router&#x2F;api&#x2F;bar&#x2F;attendance&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;router&#x2F;api&#x2F;chat&#x2F;room&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;router&#x2F;api&#x2F;configuration&#x2F;modules&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;router&#x2F;api&#x2F;connection&#x2F;statistics&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;router&#x2F;api&#x2F;media&#x2F;videos&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;router&#x2F;api&#x2F;poi&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;del&gt;&lt;code&gt;&#x2F;router&#x2F;api&#x2F;train&#x2F;coverage&lt;&#x2F;code&gt;&lt;&#x2F;del&gt; (no longer exists as of &lt;code&gt;2025-09-24&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;router&#x2F;api&#x2F;train&#x2F;details&lt;&#x2F;code&gt;, or &lt;code&gt;&#x2F;router&#x2F;api&#x2F;train&#x2F;progress&lt;&#x2F;code&gt; (they are, as far as I can remember, the same)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;router&#x2F;api&#x2F;train&#x2F;gps&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;“Meh”_Endpoints&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#“Meh”_Endpoints&quot; aria-label=&quot;Anchor link for: “Meh”_Endpoints&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
“Meh” Endpoints&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;&#x2F;router&#x2F;api&#x2F;chat&#x2F;room&lt;&#x2F;code&gt; was an endpoint that was unexpectedly disappointing. If memory serves me right, it only provided very simple descriptions of buttons on the on-board assistance chat service, which were not interesting to me. Same goes for &lt;code&gt;&#x2F;router&#x2F;api&#x2F;configuration&#x2F;modules&lt;&#x2F;code&gt;, I did not even save it, and I cannot remember what its purpose was. Whenever I take a TGV again, I will have to dig again. I am confident, however, that if past me did not save them, then they had a good reason not to do so, as they were probably fairly useless when it comes to extracting data from the portal.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;The_Bar&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#The_Bar&quot; aria-label=&quot;Anchor link for: The_Bar&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
The Bar&lt;&#x2F;h3&gt;
&lt;p&gt;You can fetch an endpoint to know whether or not there is currently a queue at the on-train bar! It’s given to you by &lt;code&gt;&#x2F;api&#x2F;router&#x2F;bar&#x2F;attendance&lt;&#x2F;code&gt;, and returns an object with a single boolean called &lt;code&gt;isBarQueueEmpty&lt;&#x2F;code&gt; which tells you whether the bar is busy at the moment or not.&lt;&#x2F;p&gt;
&lt;p&gt;It’s effectively useless. I am pretty sure it needs manual update from whoever behind the counter is running the bar, and they probably have other things to worry about.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;The_Media&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#The_Media&quot; aria-label=&quot;Anchor link for: The_Media&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
The Media&lt;&#x2F;h3&gt;
&lt;p&gt;This might be the only category where I did not save any example of the JSON output. Essentially, the web portal contains little promotional videos the SNCF made to showcase advice to passengers and such. It’s mostly promotional and boring. It has little gems &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gateway.ipfs.io&#x2F;ipfs&#x2F;QmRRg5gVmL8kaecTej3ujak3ib69XMQzf7UQ4agZKbhFtK&quot;&gt;here and there&lt;&#x2F;a&gt; however, but I did not bother viewing it all.&lt;&#x2F;p&gt;
&lt;p&gt;I did, however, bother downloading all 4.3GB of it:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;vulpinecitrus.info&#x2F;blog&#x2F;the-sncf-wifi-api&#x2F;2023-08-26_00-14.png&quot; title=&quot;Media%20Folders%20Screenshot&quot; alt=&quot;Screenshot of a list of folders, which total content amounts to 4.3GB&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Once I’m done inspecting it beyond making sure all files are valid video files and thumbnails, I will think about archiving them on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;archive.org&#x2F;&quot;&gt;archive.org&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The precise endpoint that delivers all paths and languages available for videos is &lt;code&gt;https:&#x2F;&#x2F;wifi.sncf&#x2F;router&#x2F;api&#x2F;media&#x2F;videos&lt;&#x2F;code&gt;. Videos are grouped in categories (&lt;code&gt;inoui-coulisses&lt;&#x2F;code&gt;, &lt;code&gt;inoui-idees&lt;&#x2F;code&gt;, &lt;code&gt;inoui-pub&lt;&#x2F;code&gt;, &lt;code&gt;tgv&lt;&#x2F;code&gt;), and available in multiple languages (I found &lt;code&gt;DE&lt;&#x2F;code&gt;, &lt;code&gt;IT&lt;&#x2F;code&gt;, &lt;code&gt;ES&lt;&#x2F;code&gt;, &lt;code&gt;EN&lt;&#x2F;code&gt; and of course &lt;code&gt;FR&lt;&#x2F;code&gt;). Or at least, they should be: from what I saw while inspecting the videos, all of them have audio tracks in french.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#&quot; aria-label=&quot;Anchor link for: &quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
WiFi Metrics&lt;&#x2F;h3&gt;
&lt;p&gt;In the settings area of the WiFi portal, you have a section that gives you an indication of your signal strength and the count of devices currently connected from anywhere else on the train. Spoiler: it’s also pulled from a readily accessible endpoint called &lt;code&gt;&#x2F;router&#x2F;api&#x2F;connection&#x2F;statistics&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The data it returns is simple:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;quality&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;devices&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 246&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;.quality&lt;&#x2F;code&gt; seems to be an integer on an unknown scale that tells you the quality of the internet access at the moment, and &lt;code&gt;.devices&lt;&#x2F;code&gt;, fairly explicitly, tells you about the total number of devices connected. Because it seems that every single one of them gets a unique &lt;code&gt;&#x2F;21&lt;&#x2F;code&gt; subnet on the train, and that inter-subnetwork filtering was in place, I did not manage to find any device on my subnetwork other than myself and the gateway.&lt;&#x2F;p&gt;
&lt;p&gt;I have to commend the SNCF, however, on being able to handle that many machines being connected at the same time. Hopefully the end terminals do not use as much bandwidth as, let’s say, a League of Legends player at a tournament event (&lt;em&gt;sigh&lt;&#x2F;em&gt;).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;-1&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#-1&quot; aria-label=&quot;Anchor link for: -1&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
Maps, POIs, GPS&lt;&#x2F;h3&gt;
&lt;p&gt;On the WiFi portal, there is a nice little map of your trip. For example, one of my trains had this trip:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;vulpinecitrus.info&#x2F;blog&#x2F;the-sncf-wifi-api&#x2F;2023-08-26_00-18.png&quot; title=&quot;Screenshot%20of%20the%20map%20showing%20a%20purple%20trail%20from%20Paris%20to%20Rennes%20with%20a%20lot%20of%20little%20drop%20pins%20with%20pictures%20around%20the%20path,%20and%20the%20icon%20of%20a%20train%20somewhere%20on%20it&quot; alt=&quot;Screenshot of the map showing a purple trail from Paris to Rennes with a lot of little drop pins with pictures around the path, and the icon of a train somewhere on it&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The map contains several interesting things: POIs of notable sightseeing points around the map, the precise routing scheduled to be taken by the train, all the stations you will go through, and your progress. I will keep the progress for later, because I had quite a lot of fun with it (that was sort of my primary goal ever since I heard about the WiFi API).&lt;&#x2F;p&gt;
&lt;p&gt;First, the API gives you exact positioning when available. The endpoint &lt;code&gt;&#x2F;router&#x2F;api&#x2F;train&#x2F;gps&lt;&#x2F;code&gt; provides a nice little JSON that looks like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;success&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;fix&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;timestamp&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1692349499&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;latitude&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 45.226723333&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;longitude&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -0.150826667&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;altitude&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 76.72&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;speed&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 83.906&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;heading&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 26.2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You’ve got everything you may want. Exact GPS coordinates (longitude, latitude, altitude), heading, speed, a timestamp, and a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;support.dewesoft.com&#x2F;en&#x2F;support&#x2F;solutions&#x2F;articles&#x2F;14000108531-explanation-of-gps-fix-quality-values&quot;&gt;GPS fix&lt;&#x2F;a&gt;, which seems to essentially be an identifier for which method was used to measure the position. That detail can help getting a sense of the precision provided at a given time by the measurement method. &lt;strong&gt;Later Addition&lt;&#x2F;strong&gt;: as a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;JonesJugHead&quot;&gt;kind reader&lt;&#x2F;a&gt; pointed out to me by email, the speed is provided in meters per second. It seemed obvious to me at the time, but out of context it’s hard to surmise.&lt;&#x2F;p&gt;
&lt;p&gt;At the same time, the map displays a lot of &lt;em&gt;POI icons&lt;&#x2F;em&gt; with landmarks around the area you travel through, and more. All of these POIs are available in &lt;code&gt;&#x2F;router&#x2F;api&#x2F;poi&lt;&#x2F;code&gt;, which returns you a &lt;em&gt;really huge&lt;&#x2F;em&gt; object with entries in this format:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    &amp;quot;id&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 20936&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    &amp;quot;title&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Abbaye des Prémontrés en Lorraine&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    &amp;quot;button&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Voir plus&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    &amp;quot;latitude&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 48.907502&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    &amp;quot;longitude&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 6.057966&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    &amp;quot;image&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&#x2F;poi&#x2F;images&#x2F;20936&#x2F;small.jpg&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    &amp;quot;isEvent&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    &amp;quot;visibleWhenZoomOut&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    &amp;quot;article&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;header&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;header_title&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Abbaye des Prémontrés en Lorraine&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;image&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&#x2F;poi&#x2F;images&#x2F;20936&#x2F;big.jpg&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;legend_image&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Abbaye de Prémontré en Lorraine © Brigitte Merle &#x2F; Photononstop&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;department&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;France &amp;gt; Grand Est &amp;gt; Meurthe-et-Moselle &amp;gt; Pont-à-Mousson&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;content&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;title_POI&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&amp;lt;p&amp;gt;&amp;lt;span&amp;gt;&amp;lt;span&amp;gt;&amp;lt;span&amp;gt;&amp;lt;span&amp;gt;&amp;lt;span&amp;gt;Entre &amp;lt;strong&amp;gt;Metz &amp;lt;&#x2F;strong&amp;gt;et &amp;lt;strong&amp;gt;Nancy, en&amp;lt;&#x2F;strong&amp;gt;&amp;lt;&#x2F;span&amp;gt;&amp;lt;&#x2F;span&amp;gt;&amp;lt;&#x2F;span&amp;gt;&amp;lt;&#x2F;span&amp;gt;&amp;lt;&#x2F;span&amp;gt; Lorraine, la ville de Pont-à-Mousson abrite une abbaye du début du XVIIIe siècle, classée monument historique. L’abbaye des Prémontrés accueille un centre culturel, se visite et propose même des chambres pour y pas [...]&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;title&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Abbaye des Prémontrés en Lorraine&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;text&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&amp;lt;br&#x2F;&amp;gt;&amp;lt;br&#x2F;&amp;gt;&amp;lt;h2&amp;gt;Explorez l&amp;#39;abbaye des Prémontés :&amp;lt;&#x2F;h2&amp;gt;&amp;lt;h2&amp;gt;L&amp;#39;histoire de l&amp;#39;abbaye&amp;lt;&#x2F;h2&amp;gt;&amp;lt;p&amp;gt;&amp;lt;span&amp;gt;&amp;lt;span&amp;gt;&amp;lt;span&amp;gt;&amp;lt;span&amp;gt;&amp;lt;span&amp;gt;Bâtie au début du XVIIIe siècle, l’abbaye a connu des périodes de faste mais aussi d’abandon. Incendie, révolution, réquisition, encore incendie…elle a été détruite, pillée, vidée, réquisitionnée pour être transformée en hôpital &amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;footer&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;author&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;Coralie Salvi &amp;lt;br&#x2F;&amp;gt; Rédaction SNCF Connect&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;update_article&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;2022-10-14&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;  },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For those who do not read french, you have: identifier, title, the name of a button to “see more”, a small and large thumbnail, and a bunch of HTML to describe the POI (in &lt;code&gt;.content&lt;&#x2F;code&gt;). You also get to see credits for the photographs, and the person who entered this entry into the database of SNCF (thanks Coralie). These POIs can also seemingly be events, which I have never seen, but I can imagine the purpose of, if a commercial event is happening and you want to show it on your map.&lt;&#x2F;p&gt;
&lt;p&gt;As for the thumbnails? Of course I downloaded the whole 35MB or so of them.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, there is &lt;code&gt;&#x2F;router&#x2F;api&#x2F;train&#x2F;coverage&lt;&#x2F;code&gt;, which is kind of bizarre. It’s a collection of series of GPS coordinates:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;type&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;FeatureCollection&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;features&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;type&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Feature&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;geometry&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;type&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;LineString&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;coordinates&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            1.454419&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            43.611391&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            1.454473&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            43.611895&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            1.454464&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            43.612209&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            1.454158&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            43.612884&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;             ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;properties&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;quality&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;small&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;type&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Feature&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;geometry&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;type&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;LineString&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;coordinates&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            1.4384&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            43.635599&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            1.43475&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            43.639033&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            1.434588&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;            43.639303&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;	      &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   	    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;   	  }&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;      &amp;quot;properties&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;quality&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;small&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FDAEB7;font-style: italic;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I will be honest, I don’t really know what to do about it. My guess is that it draws the path the train takes on the map? I assume so, at least. &lt;strong&gt;Later addition&lt;&#x2F;strong&gt;: this was the single known API endpoint i could
fetch again in September 2024. i cannot say if it was removed or if it was broken
for my particular trip, but it really doesn’t help me understand its purpose.
&lt;strong&gt;Later later addition&lt;&#x2F;strong&gt;: Confirmed in September 2025 that this endpoint no longer exists.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;-2&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#-2&quot; aria-label=&quot;Anchor link for: -2&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
Trip Details&lt;&#x2F;h3&gt;
&lt;p&gt;This is the most interesting and exploitable part of the data the API hands to you. My end goal was to produce a tool that could help me track the progress of my train across its trip while remaining in the terminal. Of course, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eldritch.cafe&#x2F;@SharpLimefox&#x2F;110910388718103442&quot;&gt;I did it&lt;&#x2F;a&gt; after a ton of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eldritch.cafe&#x2F;@SharpLimefox&#x2F;110909873661102660&quot;&gt;&lt;code&gt;jq&lt;&#x2F;code&gt; manipulation&lt;&#x2F;a&gt;. The original payload looks like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;number&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;8504&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;carrier&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;INOUI&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;events&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;onboardServices&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;quot;OCEHP&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;quot;OCEVP&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;quot;OCECM&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;quot;OCEUB&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;quot;OCEBA&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;quot;OCEWF&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;    &amp;quot;OCEPP&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;additionalServices&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;stops&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;code&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;FRXYT&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;label&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Toulouse Matabiau&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;services&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;DRIVER&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;coordinates&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;latitude&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 43.611206&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;longitude&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1.453616&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;progress&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;progressPercentage&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 100&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;traveledDistance&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 45628.872278306364&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;remainingDistance&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;theoricDate&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;2023-08-18T06:28:00.000Z&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;realDate&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;2023-08-18T06:28:00.000Z&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;isRemoved&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;isCreated&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;isDiversion&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;delay&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;isDelayed&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;duration&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;code&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;FRXMW&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;label&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Montauban Ville Bourbon&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;services&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;DRIVER&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;coordinates&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;latitude&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 44.01444&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;longitude&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1.341499&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;progress&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;progressPercentage&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 34.13992504047737&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;traveledDistance&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 20981.52831506503&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;remainingDistance&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 40475.92447719702&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;theoricDate&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;2023-08-18T06:54:00.000Z&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;realDate&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;2023-08-18T06:54:00.000Z&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;isRemoved&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;isCreated&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;isDiversion&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;delay&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;isDelayed&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;duration&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;code&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;FRAGF&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;label&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Agen&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;platform&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;2&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;services&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;DRIVER&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;coordinates&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;latitude&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 44.207967&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;longitude&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0.620867&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;progress&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;progressPercentage&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;traveledDistance&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;remainingDistance&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 115660.51721035445&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;theoricDate&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;2023-08-18T07:32:00.000Z&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;realDate&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;2023-08-18T07:32:00.000Z&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;isRemoved&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;isCreated&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;isDiversion&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;delay&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;isDelayed&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;duration&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;code&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;FRBOJ&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;label&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Bordeaux Saint-Jean&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;services&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;DRIVER&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;coordinates&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;latitude&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 44.825873&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;longitude&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -0.556697&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;progress&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;progressPercentage&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;traveledDistance&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;remainingDistance&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 496038.162231625&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;theoricDate&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;2023-08-18T08:40:00.000Z&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;realDate&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;2023-08-18T08:40:00.000Z&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;isRemoved&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;isCreated&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;isDiversion&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;delay&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;isDelayed&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;duration&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;code&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;FRPMO&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;label&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;Paris - Montparnasse - Hall 1 &amp;amp; 2&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;services&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;DRIVER&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;coordinates&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;latitude&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 48.841172&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        &amp;quot;longitude&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 2.320514&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;theoricDate&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;2023-08-18T10:52:30.000Z&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;realDate&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;2023-08-18T10:52:30.000Z&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;isRemoved&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;isCreated&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;isDiversion&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;delay&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;isDelayed&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;      &amp;quot;duration&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;trainId&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;882&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It’s quite intricate, but essentially contains:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Information about services on-board (codes that I haven’t cracked in &lt;code&gt;.onboardServices&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Information about the various stops in &lt;code&gt;.stops&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Lengths and estimated distance across stops (&lt;code&gt;.stops[..].progress&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;An identifier for your train (&lt;code&gt;.trainId&lt;&#x2F;code&gt;), mine was &lt;code&gt;882&lt;&#x2F;code&gt; that day!&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Now, each stop is a little intricate as a data structure. You get the hilarious confirmation in &lt;code&gt;.services.DRIVER&lt;&#x2F;code&gt; that you &lt;strong&gt;actually have someone to drive the train&lt;&#x2F;strong&gt; at each station, which is cool. There are details about the station, like a unique code, its human-readable name, coordinate, and such. You have date information, the time you were theoretically supposed to arrive at&#x2F;leave a station, and the actual time you did. Finally, you get some booleans that inform you of changes that might have happened to your original route, and some delay information. For me, when traveling across the segment between Agen and Bordeaux Saint-Jean, the details data suddenly foretold 5 minutes of &lt;code&gt;.delay&lt;&#x2F;code&gt; due to “Large attendance” or something (the station was packed and busy, essentially).&lt;&#x2F;p&gt;
&lt;h4 id=&quot;-3&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#-3&quot; aria-label=&quot;Anchor link for: -3&quot;&gt;####&lt;&#x2F;a&gt;&amp;nbsp;
Progress Details&lt;&#x2F;h4&gt;
&lt;p&gt;And then we get to the details, which do not work exactly as you would expect. Each stop contains the progress information from its start to the next. You can therefore identify the last stop of your trip not only by the fact it is last in your &lt;code&gt;.stops&lt;&#x2F;code&gt; but also because it does not have any &lt;code&gt;.progress&lt;&#x2F;code&gt; data. You have three values for each segment &lt;code&gt;X -&amp;gt; Y&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.traveledDistance&lt;&#x2F;code&gt;, which is the length you have already traveled along the segment, in meters&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;.remainingDistance&lt;&#x2F;code&gt;, the length that remains on the segment, in meters&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;.progressPercentage&lt;&#x2F;code&gt;, the result of &lt;code&gt;(.traveledDistance)&#x2F;(.traveledDistance + .remainingDistance) * 100&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This particular format is probably fairly modular when it comes to suddenly modifying trips on the fly in case a train needs to be rerouted. Since your trip is only divided into segments, you can re-compute the total distance traveled and such from individual segments in case of modification.&lt;&#x2F;p&gt;
&lt;p&gt;It was a bit more painful to script for me however, because that meant a lot of logic had to go into summing up the lengths traveled, the lengths remaining, and compute the final ratio myself&lt;&#x2F;p&gt;
&lt;h4 id=&quot;-4&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#-4&quot; aria-label=&quot;Anchor link for: -4&quot;&gt;####&lt;&#x2F;a&gt;&amp;nbsp;
Scripting the Details&lt;&#x2F;h4&gt;
&lt;p&gt;Obtaining a percentage of your trip is done by summing up the distance traveled across all segments with the length remaining, and doing a ratio. Once you have a percentage of your position, the rest is simple arithmetic, which leads to this atrocity of a one-liner:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -sL&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;https:&#x2F;&#x2F;wifi.sncf&#x2F;router&#x2F;api&#x2F;train&#x2F;details&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;	|&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; jq&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -Mc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.stops | map(select (.progress != null)) | [ (map(.progress.traveledDistance) | add), (map(.progress.remainingDistance) | add)] | if (.[0] + .[1]) then &amp;quot;\(.[0] &#x2F; (.[0] + .[1]) * 100)%&amp;quot; else &amp;quot;EEE.EE%&amp;quot; end&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;which will show you the progress in &lt;code&gt;3.2f&lt;&#x2F;code&gt; format. Also, yes, &lt;strong&gt;that is almost purely arithmetic done in &lt;code&gt;jq&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;. I learned a lot about &lt;code&gt;jq&lt;&#x2F;code&gt; during my train trip.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;-5&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#-5&quot; aria-label=&quot;Anchor link for: -5&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Later Additions&lt;&#x2F;h2&gt;
&lt;p&gt;By the time i am writing this section it has been almost a year since this i published the first version of this blog post, which seems to have garnered a lot of attention (in the form of multiple emails of people either thanking for this information, and pointing me to tools they made to use it or pointing out information i missed the first time).&lt;&#x2F;p&gt;
&lt;p&gt;One later addition i can make which fits nowhere is that when the train hasn’t started, the only reply from the query is:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;  &amp;quot;trainId&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;XXX&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Where &lt;code&gt;XXX&lt;&#x2F;code&gt; is the train identifier (for example, &lt;code&gt;882&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;-6&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#-6&quot; aria-label=&quot;Anchor link for: -6&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
In Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;It took a while for me to write this. This should come out some time in mid-October, and I was on the train in mid-August. Life’s moving fast, I had enough time to even &lt;em&gt;begin my PhD&lt;&#x2F;em&gt;, so that’s that.&lt;&#x2F;p&gt;
&lt;p&gt;As to what I take away from this?&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Nobody is going to bother you for grabbing data that is freely accessible&lt;&#x2F;li&gt;
&lt;li&gt;Make weird tools with it! Who cares! Make cute GUIs and TUIs with train emoji 🚂!&lt;&#x2F;li&gt;
&lt;li&gt;Document everything you find, and everything you reverse. If it’s not useful to you, it could be to someone else.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Rust for Linux Basics: Handling Function Pointers</title>
        <published>2023-10-09T00:00:00+00:00</published>
        <updated>2023-10-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/rust-for-linux-basics-handling-function-pointers/"/>
        <id>https://vulpinecitrus.info/blog/rust-for-linux-basics-handling-function-pointers/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/rust-for-linux-basics-handling-function-pointers/">&lt;p&gt;&lt;strong&gt;Note&lt;&#x2F;strong&gt;: I originally wrote this as a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;rust-for-linux.zulipchat.com&#x2F;#narrow&#x2F;stream&#x2F;396592-Networking&#x2F;topic&#x2F;Handling.20Function.20Pointers&quot;&gt;message in the RFL Zulip chat&lt;&#x2F;a&gt; answering a question from someone who asked about ways to handle function points in Rust for Linux, especially in the context of &lt;code&gt;net&lt;&#x2F;code&gt;, where we do it quite often. This blog post is a slightly refined version of that message, where I got carried away and essentially infodumped on the poor fella. I am a silly fox 🦊&lt;&#x2F;p&gt;
&lt;p&gt;Fun fact! A while back I originally planned to write a blog post about the very process of me figuring this whole thing out again from scratch, which I &lt;em&gt;accidentally published&lt;&#x2F;em&gt; for a couple days while unfinished. Oops.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;vulpinecitrus.info&#x2F;blog&#x2F;rust-for-linux-basics-handling-function-pointers&#x2F;ffi-post.png&quot; title=&quot;Screenshot%20of%20my%20unpublished%20post%20called%20Rust%20FFI%20Callbacks%20for%20the%20Kernel%20at%20Compile%20Time&quot; alt=&quot;Screenshot of my unpublished post: Rust FFI Callbacks for the Kernel at Compile Time&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Here’s a little explainer on how I handled pointers. It’s not far from what I have seen others do, and there might be things that are considered to be common patterns&#x2F;good practices that I sidestepped&#x2F;skipped. I’m just learning. Thankfully, I had to explain this very thing many times to a handful of people, so it should be somewhat structured.&lt;&#x2F;p&gt;
&lt;p&gt;I’ll take the example of my &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;Lymkwi&#x2F;linux&#x2F;src&#x2F;branch&#x2F;rust-net-drivers&#x2F;rust&#x2F;kernel&#x2F;net&#x2F;gro.rs#L64&quot;&gt;NAPI structure&lt;&#x2F;a&gt;, as a way of implementing one function pointer needed in a structure. From my experience of moving other function pointers around (like &lt;code&gt;struct net_device&lt;&#x2F;code&gt;’s &lt;code&gt;priv_destructor&lt;&#x2F;code&gt;, in groups&#x2F;descriptors such as RTNL, and such), it doesn’t really change too much.&lt;&#x2F;p&gt;
&lt;p&gt;It’s going to be a lot of things you might already know or find obvious because I prefer being thorough and verbose rather than accidentally missing something critical, and it might be useful for people coming at this with very little familiarity with the project.&lt;&#x2F;p&gt;
&lt;p&gt;The general idea is going to be:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Create a trait definition marked &lt;code&gt;#[vtable]&lt;&#x2F;code&gt; that contains the Rust function(s) you want to implement, with all types in the return value and arguments replaced with their Rust counterparts&lt;&#x2F;li&gt;
&lt;li&gt;Implement that trait on a structure that will define your function for your use case&lt;&#x2F;li&gt;
&lt;li&gt;Have a second type that acts like a factory, and is generic on any type that implements your trait&lt;&#x2F;li&gt;
&lt;li&gt;The factory type is going to contain the static definition of the final pointer&#x2F;series of pointers you will use, it decides which ones are defined thanks to booleans created at the implementation step of a &lt;code&gt;#[vtable]&lt;&#x2F;code&gt; trait&lt;&#x2F;li&gt;
&lt;li&gt;The functions being pointed to will wrap around your actual implementation, receiving arguments with binding types, and converting them, hiding away all of the &lt;code&gt;unsafe {}&lt;&#x2F;code&gt; from the driver user, before calling your implementation with the abstracted arguments. It does the reverse operation for any return value your Rust implementation gives&lt;&#x2F;li&gt;
&lt;li&gt;When you need the pointer in Rust code, you can call a method that returns a reference to the static stored for the specific version of your factory type for the trait of the implementer, and have an abstraction wrapper set it&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#&quot; aria-label=&quot;Anchor link for: &quot;&gt;####&lt;&#x2F;a&gt;&amp;nbsp;
Step 0: Prerequisites&lt;&#x2F;h4&gt;
&lt;p&gt;You should identify the types of your function arguments and return type on the C side. Prepare abstractions for those if not already. For the case of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.5.6&#x2F;source&#x2F;include&#x2F;linux&#x2F;netdevice.h#L348&quot;&gt;napi polling&lt;&#x2F;a&gt;, you get a &lt;code&gt;struct napi_struct*&lt;&#x2F;code&gt; and an &lt;code&gt;int&lt;&#x2F;code&gt;, and return an &lt;code&gt;int&lt;&#x2F;code&gt;. Because I was already writing an abstraction for using &lt;code&gt;struct napi_struct&lt;&#x2F;code&gt;, I was all good, and could convert back and forth from &lt;code&gt;struct napi_struct*&lt;&#x2F;code&gt; and &lt;code&gt;&amp;amp;Napi&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;&amp;amp;mut Napi&lt;&#x2F;code&gt;. That return &lt;code&gt;int&lt;&#x2F;code&gt; is not meant to be signaling errors as far as I know, only the number of packets received, so the stack can know how many packets were received in that poll run.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;-1&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#-1&quot; aria-label=&quot;Anchor link for: -1&quot;&gt;####&lt;&#x2F;a&gt;&amp;nbsp;
Step 1: Making a Trait&lt;&#x2F;h4&gt;
&lt;p&gt;The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Rust-for-Linux&#x2F;linux&#x2F;blob&#x2F;b2516f7af9d238ebc391bdbdae01ac9528f1109e&#x2F;rust&#x2F;macros&#x2F;vtable.rs&quot;&gt;&lt;code&gt;#[vtable]&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; macro was created for these kinds of scenarios where you need to have a sort of “table” of function definitions (on the Rust side, on the C side it’s pointers), and know which ones have been defined by an implementation.&lt;&#x2F;p&gt;
&lt;p&gt;Say I have:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F;&#x2F; NAPI poller definition trait&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[vtable]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pub trait&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; NapiPoller&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F;&#x2F; Implementation of the poll function&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; poll&lt;&#x2F;span&gt;&lt;span&gt;(_napi&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;: &amp;amp;mut&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Napi&lt;&#x2F;span&gt;&lt;span&gt;, _budget&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; i32&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; i32&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; &#x2F;&#x2F; Not implemented&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;Lymkwi&#x2F;linux&#x2F;src&#x2F;branch&#x2F;rust-net-drivers&#x2F;rust&#x2F;kernel&#x2F;net&#x2F;gro.rs#L20&quot;&gt;(actual version here)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;-2&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#-2&quot; aria-label=&quot;Anchor link for: -2&quot;&gt;####&lt;&#x2F;a&gt;&amp;nbsp;
Step 2: Make a builder&lt;&#x2F;h4&gt;
&lt;p&gt;The builder&#x2F;factory is going to hold your pointer definition(s) and give you static methods to retrieve it. In my case I even defined the exact type of the poller function as a &lt;code&gt;type&lt;&#x2F;code&gt; because it was just a bit too annoying to type out in its entirety.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F;&#x2F; Building structure for poller functions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pub struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; PollerBuilder&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;T&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; NapiPoller&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    _p&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; PhantomData&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;T&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; PollerFunction&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; = unsafe extern&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;C&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; fn&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*mut&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; bindings&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;napi_struct,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; i32&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; i32&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You’ve probably seen it already, but function pointers on the Rust side are &lt;code&gt;Option&amp;lt;unsafe extern &quot;C&quot; fn(A....) -&amp;gt; B&amp;gt;&lt;&#x2F;code&gt;, and we keep them at &lt;code&gt;None&lt;&#x2F;code&gt; if nothing is provided.&lt;&#x2F;p&gt;
&lt;p&gt;The builder implementation is valid for any &lt;code&gt;T: NapiPoller&lt;&#x2F;code&gt;, and it holds my static function definition:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;impl&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;T&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; NapiPoller&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; PollerBuilder&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;T&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; FUNC&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Option&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;PollerFunction&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;T&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;HAS_POLLER&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;then_some&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;Self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;poller_callback);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F;&#x2F; Access the function pointer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    pub const fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; build_function&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Option&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;PollerFunction&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;        Self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;FUNC&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    unsafe extern&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;C&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; poller_callback&lt;&#x2F;span&gt;&lt;span&gt;(napi&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;: *mut&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; bindings&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;napi_struct, budget&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; i32&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; i32&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        &#x2F;&#x2F;&#x2F; SAFETY: &amp;lt;cut for brevity&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; napi&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;: &amp;amp;mut&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Napi&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; = unsafe&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp;mut *&lt;&#x2F;span&gt;&lt;span&gt;napi&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;cast&lt;&#x2F;span&gt;&lt;span&gt;() };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        &#x2F;&#x2F; The rest is primitive, hence, trivial&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;T&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;poll&lt;&#x2F;span&gt;&lt;span&gt;(napi, budget)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At the time &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;Lymkwi&#x2F;linux&#x2F;src&#x2F;branch&#x2F;rust-net-drivers&#x2F;rust&#x2F;kernel&#x2F;net&#x2F;gro.rs#L43&quot;&gt;I did my version&lt;&#x2F;a&gt;, I forgot to check &lt;code&gt;&amp;lt;T&amp;gt;::HAS_POLL&lt;&#x2F;code&gt;, and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;stable&#x2F;std&#x2F;primitive.bool.html#method.then_some&quot;&gt;&lt;code&gt;bool::then_some&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; was only recently stable, and I did not use it.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;-3&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#-3&quot; aria-label=&quot;Anchor link for: -3&quot;&gt;####&lt;&#x2F;a&gt;&amp;nbsp;
Step 3: Implement in user and abstractions&lt;&#x2F;h4&gt;
&lt;p&gt;Let’s say I have my drive, and it needs to have a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;Lymkwi&#x2F;linux&#x2F;src&#x2F;branch&#x2F;rust-net-drivers&#x2F;drivers&#x2F;net&#x2F;rustypipe&#x2F;device.rs#L458&quot;&gt;definition of NAPI polling&lt;&#x2F;a&gt;. You put whatever you want in it. As a fun thought experiment, if you do not provide an implementation of &lt;code&gt;poll&lt;&#x2F;code&gt;, you can imagine that the factory structure will contain &lt;code&gt;None&lt;&#x2F;code&gt; in its const field, and that your assignment will be to a &lt;code&gt;null&lt;&#x2F;code&gt; function pointer. That fits the semantics of what we want if we do not define a field in a descriptor&#x2F;set a function pointer to null from a lack of implementation.&lt;&#x2F;p&gt;
&lt;p&gt;Oh and your implementation also has to be marked &lt;code&gt;#[vtable]&lt;&#x2F;code&gt; so it can process it and add the booleans indicating whether you overwrote functions or not. I really wish we had some way to do that in the core language, but I think we’re in such a specific use case that it might never come to &lt;code&gt;core&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Now, for my poller, I needed an additional function that sets the &lt;code&gt;poll&lt;&#x2F;code&gt; field of &lt;code&gt;struct napi_struct&lt;&#x2F;code&gt; through my abstraction, so I wrote the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;Lymkwi&#x2F;linux&#x2F;src&#x2F;branch&#x2F;rust-net-drivers&#x2F;rust&#x2F;kernel&#x2F;net.rs#L398&quot;&gt;wrapper for it&lt;&#x2F;a&gt; (in my &lt;code&gt;net::Device&lt;&#x2F;code&gt;, which I guess made sense at the time), and this neat little trick I found helps me pass the &lt;em&gt;trait implementer&lt;&#x2F;em&gt; type for my implementation of &lt;code&gt;poll&lt;&#x2F;code&gt; to the function:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pub fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; napi_add&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;POLLER&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; gro&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;NapiPoller&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span&gt;, napi&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;: &amp;amp;mut&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; gro&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Napi&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; ... conversion stuff&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; Use our factory type on the type provided to retrieve its implementation as a const pointer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; that way we can pass it around on the C side and it will remain valid, and hide all of the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; wrapping from the Rust user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; poll_func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; gro&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;PollerBuilder&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;POLLER&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;build_function&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F;&#x2F; SAFETY: ....&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    unsafe&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; bindings&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;netif_napi_add&lt;&#x2F;span&gt;&lt;span&gt;(dev_ptr, napi_ptr, poll_func) };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And in my driver:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dev&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;napi_add&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;MyNapiPoller&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; napi);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;-4&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#-4&quot; aria-label=&quot;Anchor link for: -4&quot;&gt;####&lt;&#x2F;a&gt;&amp;nbsp;
Limitations&lt;&#x2F;h4&gt;
&lt;p&gt;This is only an example but it outlines the general steps I undertook for RTNL, NAPI, and various other function pointers. I got them from looking at code others made, and things like &lt;code&gt;#[vtable]&lt;&#x2F;code&gt;  make me think this general structure is intended to be used, at least for now.&lt;&#x2F;p&gt;
&lt;p&gt;In terms of scaling? I haven’t evaluated it, but I assumed that changing function pointers on the fly is going to be a bit of a bother. Hopefully you do not actually need to have twenty of fifty different implementations, and you only have to implement one trait in the user. On the abstraction side, however, it gets problematic. If you are talking about descriptors&#x2F;structures of many pointers, doing housekeeping to keep the names up to date is necessary (I believe this has been discussed in the recent proposal in &lt;code&gt;netdev&lt;&#x2F;code&gt;). Furthermore, it’s still a lot of boilerplate code for &lt;em&gt;one&lt;&#x2F;em&gt; function pointer, and if you do not have any backing structure, you may need to spend a lot of time making structures that are needed &lt;em&gt;just&lt;&#x2F;em&gt; to handle that function pointer.&lt;&#x2F;p&gt;
&lt;p&gt;Ah and don’t forget: my code hasn’t been reviewed by people on here. Handle it with an amount of salt typically reserved for a profoundly bland dish.&lt;&#x2F;p&gt;
&lt;p&gt;That’s all I can think of for now, I might have gone a bit overboard with documenting this (I like writing documentation). None of this is proofread either, it’s all just pure stream of thoughts, I hope it made sense at all. Hopefully it was useful in some way, and I will try and hang around to answer questions&#x2F;fix issues people could raise if I said something wrong.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Rust for Linux Basics: Adding Allowed Features</title>
        <published>2023-09-10T00:00:00+00:00</published>
        <updated>2023-09-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/rust-for-linux-basics-adding-allowed-features/"/>
        <id>https://vulpinecitrus.info/blog/rust-for-linux-basics-adding-allowed-features/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/rust-for-linux-basics-adding-allowed-features/">&lt;p&gt;In order to share some of the things I’ve been doing over &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;rust-for-linux.com&#x2F;&quot;&gt;Rust for Linux&lt;&#x2F;a&gt;, I decided I would start a small series of tiny posts that demystify and detail very simple operations that can be confusing when doing development for RFL.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Rust_Features&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Rust_Features&quot; aria-label=&quot;Anchor link for: Rust_Features&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Rust Features&lt;&#x2F;h2&gt;
&lt;p&gt;Rust features go through a lifecycle where they can begin as “unstable”, and then eventually stabilized once Rust maintainers can guarantee that it will henceforth be backwards compatible, and free of memory errors (if &lt;code&gt;unsafe {}&lt;&#x2F;code&gt; is used).&lt;&#x2F;p&gt;
&lt;p&gt;Our example here is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;boxed&#x2F;struct.Box.html#method.try_new_in&quot;&gt;&lt;code&gt;Box::try_new&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, which is still nightly&#x2F;experimental. Unstable features can be used in library crates if you declare that a module is allowed to use anything behind their &lt;em&gt;feature gate&lt;&#x2F;em&gt;. &lt;code&gt;Box::try_new&lt;&#x2F;code&gt; is gated behind the &lt;code&gt;allocator_api&lt;&#x2F;code&gt; feature, meaning that if you want to use it, you need to declare that you use it at the root module of your library crate:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F;! My library crate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#![feature(allocator_api)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; You also cannot use that import unless you unlock the `allocator_api` feature gate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;use&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; core&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;alloc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;AllocError&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;pub fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; make_a_new_box&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Result&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Box&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; AllocError&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;  Box&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;try_new&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Vec&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Of course, you also need a nightly toolchain that allows you to have said feature.&lt;&#x2F;p&gt;
&lt;p&gt;What of binary crates? Well, not only do you need to use a nightly toolchain, you also need to explicitly declare in the command line that &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;error_codes&#x2F;E0725.html&quot;&gt;you’re allowing a feature&lt;&#x2F;a&gt;. For a binary crate, the list of allowed features is enabled, so you do not need the &lt;code&gt;feature&lt;&#x2F;code&gt; attribute.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Back_to_Rust_for_Linux&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Back_to_Rust_for_Linux&quot; aria-label=&quot;Anchor link for: Back_to_Rust_for_Linux&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Back to Rust for Linux&lt;&#x2F;h2&gt;
&lt;p&gt;So, why does this matter to RFL?&lt;&#x2F;p&gt;
&lt;p&gt;In the kernel, allocation is never guaranteed. You are in the kernel, so you are the huge program managing the memory, and, sometimes, there is no memory left, and you should be able to handle that (usually by gracefully unwinding and destroying all your resources, or aborting a callback, or whatever). So, if you want to &lt;code&gt;Box&lt;&#x2F;code&gt; something, you should use &lt;code&gt;try_new&lt;&#x2F;code&gt; (in fact, &lt;code&gt;Box::new&lt;&#x2F;code&gt; does not exist in RFL). Of course, if you’re going to do special things with that &lt;code&gt;Box&lt;&#x2F;code&gt;, you may use other methods, but let’s pretend we just want to &lt;code&gt;try_new&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;As of the writing of this blog post, if you pull the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Rust-for-Linux&#x2F;linux&#x2F;tree&#x2F;rust-next&quot;&gt;&lt;code&gt;rust-next&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; branch and try to write a module with a &lt;code&gt;Box::try_new&lt;&#x2F;code&gt;, it will fail. Adding the &lt;code&gt;feature&lt;&#x2F;code&gt; attribute will not help of course, because modules are not library crates. You need to add the &lt;code&gt;allocator_api&lt;&#x2F;code&gt; to the list of &lt;code&gt;allow_features&lt;&#x2F;code&gt; in the command line.&lt;&#x2F;p&gt;
&lt;p&gt;Thankfully, we are &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Rust-for-Linux&#x2F;linux&#x2F;commit&#x2F;3ed03f4da06ede71ac53cf25b9441a372e9f2487&quot;&gt;allowed to do that&lt;&#x2F;a&gt; (see &lt;code&gt;Unstable features stabilized&lt;&#x2F;code&gt;) for new modules that can be upstreamed. For example, in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lore.kernel.org&#x2F;rust-for-linux&#x2F;20230503090708.2524310-11-nmi@metaspace.dk&#x2F;&quot;&gt;null block driver patchset&lt;&#x2F;a&gt;, Andreas Hindborg adds the &lt;code&gt;allocator_api&lt;&#x2F;code&gt; so he can use &lt;code&gt;Box::try_new&lt;&#x2F;code&gt; as well.&lt;&#x2F;p&gt;
&lt;p&gt;The precise file to add that is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Rust-for-Linux&#x2F;linux&#x2F;blob&#x2F;3ed03f4da06ede71ac53cf25b9441a372e9f2487&#x2F;scripts&#x2F;Makefile.build#L277&quot;&gt;&lt;code&gt;scripts&#x2F;Makefile.build&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;make&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# Compile Rust sources (.rs)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;# ---------------------------------------------------------------------------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rust_allowed_features := new_uninit,allocator_api&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With that, you have a new allowed feature available.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>OpenStreetMap &amp; OAuth2: Do not Neglect x-www-form-urlencoded</title>
        <published>2023-08-15T00:00:00+00:00</published>
        <updated>2023-08-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/openstreetmap-oauth2-do-not-neglect-x-www-form-urlencoded/"/>
        <id>https://vulpinecitrus.info/blog/openstreetmap-oauth2-do-not-neglect-x-www-form-urlencoded/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/openstreetmap-oauth2-do-not-neglect-x-www-form-urlencoded/">&lt;p&gt;A &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;borale.si&quot;&gt;friend&lt;&#x2F;a&gt; and I were out editing for &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;openstreetmap.org&#x2F;&quot;&gt;OpenStreetMap&lt;&#x2F;a&gt;, and we wondered how we could tweak an &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;wiki.openstreetmap.org&#x2F;wiki&#x2F;Changeset#Opening_and_closing_changesets&quot;&gt;existing open changeset&lt;&#x2F;a&gt;. Because the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;vespucci.io&#x2F;&quot;&gt;client we used&lt;&#x2F;a&gt; does not seem to provide that feature, and we are messy gremlins who like to mess around with data to do things (like adding &lt;code&gt;review_requested=yes&lt;&#x2F;code&gt; to a changeset manually).&lt;&#x2F;p&gt;
&lt;p&gt;So we defaulted to the next most reasonable thing to use on our phones in the middle of the street: &lt;strong&gt;&lt;code&gt;curl&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;So I decided to finally figure out how OAuth2 works, but also fell into the trap of forgetting that &lt;code&gt;application&#x2F;x-www-form-urlencoded&lt;&#x2F;code&gt; is a thing.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;OAuth2_for_OSM&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#OAuth2_for_OSM&quot; aria-label=&quot;Anchor link for: OAuth2_for_OSM&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
OAuth2 for OSM&lt;&#x2F;h2&gt;
&lt;p&gt;For the purpose of the experiment, I created a changeset with a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.openstreetmap.org&#x2F;changeset&#x2F;139889180&quot;&gt;change I had not uploaded yet&lt;&#x2F;a&gt;, and decided to play around with the API.&lt;&#x2F;p&gt;
&lt;p&gt;OSM uses &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;wiki.openstreetmap.org&#x2F;wiki&#x2F;API_v0.6#URL_+_authentication&quot;&gt;HTTP Basic Authentication&lt;&#x2F;a&gt;, so I needed a token. The fastest way to get one seemed to be &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;wiki.openstreetmap.org&#x2F;wiki&#x2F;OAuth#OAuth_2.0_2&quot;&gt;getting it through OAuth2&lt;&#x2F;a&gt;. For that, I first &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.openstreetmap.org&#x2F;oauth2&#x2F;applications&#x2F;new&quot;&gt;registered the application&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Note that the &lt;code&gt;$REDIRECT_URI&lt;&#x2F;code&gt; you provide will be useful later. It won’t really serve any technical purpose (the authorization API just redirects you to that URI with the code you get), but if you’re missing it&#x2F;not providing the same one given at registration, you will get errors.&lt;&#x2F;p&gt;
&lt;p&gt;With registration done you get &lt;em&gt;two&lt;&#x2F;em&gt; components: &lt;code&gt;$CLIENT_ID&lt;&#x2F;code&gt; and &lt;code&gt;$CLIENT_SECRET&lt;&#x2F;code&gt;. Next, open&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;https:&#x2F;&#x2F;www.openstreetmap.org&#x2F;oauth2&#x2F;authorize?client_id=$CLIENT_ID&amp;amp;redirect_uri=$REDIRECT_URI&amp;amp;response_type=code&amp;amp;scope=write_api&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;in your browser while logged in to OSM. It’ll give you the usual “do you want to authorize this app” spiel, and you press yes. Here the scope of authorizations used here means you can only write stuff through the map API.&lt;&#x2F;p&gt;
&lt;p&gt;After authorization you will be redirected to &lt;code&gt;$REDIRECT_URI?code=$CODE&lt;&#x2F;code&gt;. Get that code, and your next step is:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -v -X&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; POST&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -L&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;https:&#x2F;&#x2F;www.openstreetmap.org&#x2F;oauth2&#x2F;token&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;	--data-urlencode&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;client_id=&lt;&#x2F;span&gt;&lt;span&gt;$CLIENT_ID&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    --data-urlencode&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;redirect_uri=&lt;&#x2F;span&gt;&lt;span&gt;$REDIRECT_URI&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    --data-urlencode&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;grant_type=authorization_code&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    --data-urlencode&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;code=&lt;&#x2F;span&gt;&lt;span&gt;$CODE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    --data-urlencode&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;client_secret=&lt;&#x2F;span&gt;&lt;span&gt;$CLIENT_SECRET&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And if you are lucky, you get:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;access_token&amp;quot;:&amp;quot;[REDACTED]&amp;quot;,&amp;quot;token_type&amp;quot;:&amp;quot;Bearer&amp;quot;,&amp;quot;scope&amp;quot;:&amp;quot;write_api&amp;quot;,&amp;quot;created_at&amp;quot;:[REDACTED]}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Hurray! But I was not so lucky.&lt;&#x2F;p&gt;
&lt;p&gt;It took me an hour and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;community.openstreetmap.org&#x2F;t&#x2F;oauth-2-0-can-not-get-access-token&#x2F;8186&#x2F;4&quot;&gt;several&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;openid.net&#x2F;specs&#x2F;oauth-v2-multiple-response-types-1_0.html&quot;&gt;unhelpful&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;7722062&#x2F;google-oauth-2-0-redirect-uri-with-several-parameters&quot;&gt;online&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;wiki.openstreetmap.org&#x2F;wiki&#x2F;OAuth&#x2F;examples&quot;&gt;pages&lt;&#x2F;a&gt; to even get the &lt;em&gt;code&lt;&#x2F;em&gt; in the first place. OpenStreetMap automatically closes changesets after one hour of inactivity, meaning mine was gone.&lt;&#x2F;p&gt;
&lt;p&gt;My friend was also tweaking things at the same time. She was surprised I got the code, so I gave her the mechanism and explained what I had tried so far, and moved on. I had tried a lot of things. For some reason, some of them made OpenStreetMap &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eldritch.cafe&#x2F;@SharpLimefox&#x2F;110890242310076021&quot;&gt;spit out errors in korean&lt;&#x2F;a&gt; or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eldritch.cafe&#x2F;@SharpLimefox&#x2F;110893581190607721&quot;&gt;spanish&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;My friend tinkered and came back with a functional method to get the bearer token. We had both found two important things:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The order of query parameters in the &lt;em&gt;authorization&lt;&#x2F;em&gt; URL was important (it’s 2023…)&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;code&gt;token&lt;&#x2F;code&gt; URL accepted neither &lt;code&gt;application&#x2F;json&lt;&#x2F;code&gt;, query params, or &lt;code&gt;text&#x2F;xml&lt;&#x2F;code&gt; for its input. After a while, I wondered if &lt;code&gt;curl&lt;&#x2F;code&gt; sending a &lt;code&gt;Content-Type: application&#x2F;x-www-form-urlencoded&lt;&#x2F;code&gt; header even without a body of data would be the problem, but removing that header also proved useless. My friend found out that you needed to provide parameters as &lt;em&gt;separate fields&lt;&#x2F;em&gt; through &lt;code&gt;--data-urlencode&lt;&#x2F;code&gt; (and we are still not sure the order does not matter).&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Eventually, after a good night’s sleep, I got my token, roughly 14 hours, including a good night’s sleep, after my changeset closed. At least, next time, I know how I can tinker with the API (albeit, perhaps, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;wiki.openstreetmap.org&#x2F;wiki&#x2F;API_v0.6#URL_+_authentication&quot;&gt;not the production API&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Merging the NFTables NAT Tables</title>
        <published>2023-06-23T00:00:00+00:00</published>
        <updated>2023-06-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/merging-the-nftables-nat-tables/"/>
        <id>https://vulpinecitrus.info/blog/merging-the-nftables-nat-tables/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/merging-the-nftables-nat-tables/">&lt;p&gt;Recently, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.debian.org&#x2F;News&#x2F;2023&#x2F;20230610&quot;&gt;a new Debian happened&lt;&#x2F;a&gt;. At this point, I am used to upgrading my machines whenever that happens. I had been hoarding Debian systems here and there since I first installed a Debian Jessie back in the day.&lt;&#x2F;p&gt;
&lt;p&gt;Among the thousand of packages being upgraded, there was &lt;code&gt;nftables&lt;&#x2F;code&gt; and &lt;code&gt;iptables&lt;&#x2F;code&gt;. A &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;links.borale.si&quot;&gt;friend of mine&lt;&#x2F;a&gt; had warned me she had heard about changes done to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;wiki.nftables.org&#x2F;wiki-nftables&#x2F;index.php&#x2F;Main_Page&quot;&gt;&lt;code&gt;nftables&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, though they would likely be backwards compatible. So, I confidently upgraded.&lt;&#x2F;p&gt;
&lt;p&gt;It turns out after rebooting my system and re-reunning my services that every single unit which needed to insert things into &lt;code&gt;nat&lt;&#x2F;code&gt;’s &lt;code&gt;POSTROUTING&lt;&#x2F;code&gt; chain could not. Specifically, I got hit with the following error from my docker service:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Jun 23 11:06:59 &amp;lt;HOSTNAME&amp;gt; dockerd[40298]: time=&amp;quot;2023-06-23T11:06:59.118341802+02:00&amp;quot; level=warning msg=&amp;quot;could not create bridge network for id d1139036d539117fca5f7c7301a9c38e1da1c725534246506364d0fd09c26c6f bridge name br-d1139036d539 while booting up from persistent state: Failed to program NAT chain: Failed to inject DOCKER in PREROUTING chain: iptables failed: iptables --wait -t nat -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER: iptables v1.8.9 (nf_tables):  CHAIN_ADD failed (File exists): chain PREROUTING\n (exit status 4)&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Docker’s integration with iptables and nftables has always been shoddy, so I wondered if it was a new thing that they had broken. I was less confident in that hypothesis when I realized my VPN tunnels had also broken (alongside every single unit that bound to its interface’s IPv4 address), because the script that sets up post-routing rules had also spit out the same errors.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_Reason&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#The_Reason&quot; aria-label=&quot;Anchor link for: The_Reason&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
The Reason&lt;&#x2F;h2&gt;
&lt;p&gt;What happens apparently is that, now, when &lt;code&gt;iptables&lt;&#x2F;code&gt; is used to insert &lt;code&gt;nat&lt;&#x2F;code&gt; rules, it tries to insert them in the table called &lt;code&gt;inet nat&lt;&#x2F;code&gt;. In &lt;code&gt;nftables&lt;&#x2F;code&gt;, tables can be split by network protocol (&lt;code&gt;inet&lt;&#x2F;code&gt;, &lt;code&gt;ipv4&lt;&#x2F;code&gt; and &lt;code&gt;ipv6&lt;&#x2F;code&gt;). I used to have two declarations of tables in my &lt;code&gt;&#x2F;etc&#x2F;nftables.conf&lt;&#x2F;code&gt;, one of which looked like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;table ip nat {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	chain POSTROUTING {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		type nat hook postrouting priority 0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		oifname &amp;quot;upstream&amp;quot; masquerade;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I theorize that &lt;code&gt;iptables&lt;&#x2F;code&gt; did not have any &lt;code&gt;inet nat&lt;&#x2F;code&gt; table (because both &lt;code&gt;ip nat&lt;&#x2F;code&gt; and &lt;code&gt;ip6 nat&lt;&#x2F;code&gt; existed), so it tried to create one, which could not work, because &lt;code&gt;inet&lt;&#x2F;code&gt; overlaps both &lt;code&gt;ip&lt;&#x2F;code&gt; and &lt;code&gt;ipv6&lt;&#x2F;code&gt;. Yet, there seems to be no fallback on trying to use the distinct &lt;code&gt;nat&lt;&#x2F;code&gt; tables.&lt;&#x2F;p&gt;
&lt;p&gt;So anyways, I fused both tables into &lt;code&gt;inet nat&lt;&#x2F;code&gt; (and used that opportunity to change the priority of &lt;code&gt;POSTROUTING&lt;&#x2F;code&gt; to &lt;code&gt;srcnat&lt;&#x2F;code&gt;), which I believe was not possible before, but do not quote me on that. Rebooted, and everything suddenly worked.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The Way I Setup My GPG Keys Now</title>
        <published>2023-04-02T00:00:00+00:00</published>
        <updated>2023-04-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/the-way-i-setup-my-gpg-keys-now/"/>
        <id>https://vulpinecitrus.info/blog/the-way-i-setup-my-gpg-keys-now/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/the-way-i-setup-my-gpg-keys-now/">&lt;blockquote&gt;
&lt;p&gt;You may find it dirty. I just think it’s neat.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Following a recent discussion with friends of mine who have made a habit of exchanging files in chats by encrypting them with GPG (for the fun (yes I have weird friends)) I thought I would make a little tutorial to explain the way that I generate and keep my keys now, because they told me they would be interested in reading that.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Reasoning&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Reasoning&quot; aria-label=&quot;Anchor link for: Reasoning&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Reasoning&lt;&#x2F;h2&gt;
&lt;p&gt;The inspiration for this methodology came from another friend whose &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.torproject.org&#x2F;&quot;&gt;programming hobbies&lt;&#x2F;a&gt; are on the kind of scale that you need a PGP key to verify your identity (again, I have weird (but very cool) friends). The idea is to view your key as having multiple components:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A central private key, which is the key used to certify that your identity&#x2F;identities is tied to other keys, signatures, etc.&lt;&#x2F;li&gt;
&lt;li&gt;Sub-keys, certified with the private one, which are used for the day-to-day operations you perform with &lt;code&gt;gpg&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Side-note: I will do the best to distinguish PGP as a standard for keys, and the &lt;code&gt;gpg&lt;&#x2F;code&gt; implementation. At some point though, I will only talk about how you can generate a similar setup as mine using &lt;code&gt;gpg2&lt;&#x2F;code&gt; (specifically &lt;code&gt;gpg2&lt;&#x2F;code&gt; version &lt;code&gt;2.2.41&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;The idea is that your central private key should stay the same as long as possible. You will, of course, keep a revocation certificate on hand to be deployed at any time, in a printed sheet of paper slid in a vault in your home, in your bank, in a bunker 100 kilometers away, and so on. With your main key never changing, you will never change key ID, and, aside from having to reupload your whole key every now and then, you do not have to bother yourself with re-verifying your identities among your web of trust.&lt;&#x2F;p&gt;
&lt;p&gt;To maintain the idea that you should not use keys eternally, notably so that attackers do not have time to attack it, you will make your sub-keys expire after a given period. Sub-keys have capabilities among three possible choices: &lt;strong&gt;A&lt;&#x2F;strong&gt;uthenticate, &lt;strong&gt;E&lt;&#x2F;strong&gt;ncrypt and &lt;strong&gt;S&lt;&#x2F;strong&gt;ign. When you do &lt;code&gt;gpg --list-keys&lt;&#x2F;code&gt;, those are the meanings of the letters you see in brackets in the core key and the sub-keys.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Generating_the_Private_Key&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Generating_the_Private_Key&quot; aria-label=&quot;Anchor link for: Generating_the_Private_Key&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Generating the Private Key&lt;&#x2F;h2&gt;
&lt;p&gt;The beginning of the whole process starts with generating the core key. I am also going to use &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;EdDSA#Ed25519&quot;&gt;Ed25519&#x2F;Cv25519&lt;&#x2F;a&gt;, which is considered to be a more modern standard, needing less data and bits of entropy to remain secure.&lt;&#x2F;p&gt;
&lt;p&gt;By default, &lt;code&gt;gpg&lt;&#x2F;code&gt; does not give you the option to use Ed25519 when you generate keys. To have that option available, as well as tweak key capabilities, you need to add the &lt;code&gt;--expert&lt;&#x2F;code&gt; flag to &lt;code&gt;gpg&lt;&#x2F;code&gt;. In addition, to have the capabilities prompt, we need to use &lt;code&gt;--full-generate-key&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;~$ gpg --expert --full-generate-key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gpg (GnuPG) 2.2.41; Copyright (C) 2022 g10 Code GmbH&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;This is free software: you are free to change and redistribute it.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;There is NO WARRANTY, to the extent permitted by law.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Please select what kind of key you want:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (1) RSA and RSA (default)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (2) DSA and Elgamal&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (3) DSA (sign only)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (4) RSA (sign only)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (7) DSA (set your own capabilities)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (8) RSA (set your own capabilities)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (9) ECC and ECC&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  (10) ECC (sign only)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  (11) ECC (set your own capabilities)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  (13) Existing key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  (14) Existing key from card&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Your selection? 11&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I select elliptic curve algorithms, but with the prompt to set my own capabilities.&lt;&#x2F;p&gt;
&lt;p&gt;The core key should only be able to &lt;strong&gt;C&lt;&#x2F;strong&gt;ertify, and that is what we will change these to:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Possible actions for a ECDSA&#x2F;EdDSA key: Sign Certify Authenticate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Current allowed actions: Sign Certify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (S) Toggle the sign capability&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (A) Toggle the authenticate capability&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (Q) Finished&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Your selection? S&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Possible actions for a ECDSA&#x2F;EdDSA key: Sign Certify Authenticate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Current allowed actions: Certify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (S) Toggle the sign capability&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (A) Toggle the authenticate capability&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (Q) Finished&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Your selection? Q&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There are actually multiple elliptic curve algorithms, but I tend to prefer Ed25519. The debate as to which one you should chose is raging in the cryptography community. I would honestly recommend you check out &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;soatok.blog&#x2F;2022&#x2F;05&#x2F;19&#x2F;guidance-for-choosing-an-elliptic-curve-signature-algorithm-in-2022&#x2F;&quot;&gt;people who know these things better than I do&lt;&#x2F;a&gt; for a more informed opinion. If you ask for my reasoning around using Ed25519… I like how it feels under my fingers when I keep typing it on my keyboard. There.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Please select which elliptic curve you want:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (1) Curve 25519&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (3) NIST P-256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (4) NIST P-384&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (5) NIST P-521&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (6) Brainpool P-256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (7) Brainpool P-384&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (8) Brainpool P-512&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (9) secp256k1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Your selection? 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As discussed earlier, the core private key should stay valid as long as needed, and only die when you need it revoked for emergency reasons.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Please specify how long the key should be valid.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;         0 = key does not expire&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;n&amp;gt;  = key expires in n days&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;n&amp;gt;w = key expires in n weeks&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;n&amp;gt;m = key expires in n months&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;n&amp;gt;y = key expires in n years&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Key is valid for? (0) 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Key does not expire at all&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Is this correct? (y&#x2F;N) y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And then you provide all of the usual information. &lt;code&gt;gpg&lt;&#x2F;code&gt; will ask you for your name, email, comment, etc. Usual stuff. The revocation certificate is stored in a path given in the sea of text at the bottom. Remember to export the private secret of your core private key to a removable medium, etc etc (these are honestly things I do not personally do, but my threat model does not involve actors that powerful).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Adding_the_Other_Sub-Keys&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Adding_the_Other_Sub-Keys&quot; aria-label=&quot;Anchor link for: Adding_the_Other_Sub-Keys&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Adding the Other Sub-Keys&lt;&#x2F;h2&gt;
&lt;p&gt;Now, if you try and call &lt;code&gt;gpg --list-keys&lt;&#x2F;code&gt; and check out your ID, you will notice you have your certification core key, and that’s it. Of course, this is not very useful. We are going to edit the key to add sub-keys that will let us do everything else we want. Once again, we need the &lt;code&gt;--expert&lt;&#x2F;code&gt; flag or else &lt;code&gt;gpg&lt;&#x2F;code&gt; will not give us the prompts we need.&lt;&#x2F;p&gt;
&lt;p&gt;As an example, I will generate the &lt;strong&gt;A&lt;&#x2F;strong&gt;uthentication key. All of the other keys are created the same way (except for the fact that the other two types of keys have a dedicated prompt so you don’t have to “set your own capabilities”:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;~$ gpg --expert --edit-key ${ID}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[snip]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gpg&amp;gt; addkey&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Please select what kind of key you want:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (3) DSA (sign only)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (4) RSA (sign only)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (5) Elgamal (encrypt only)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (6) RSA (encrypt only)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (7) DSA (set your own capabilities)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (8) RSA (set your own capabilities)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  (10) ECC (sign only)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  (11) ECC (set your own capabilities)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  (12) ECC (encrypt only)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  (13) Existing key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  (14) Existing key from card&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Your selection? 11&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Possible actions for a ECDSA&#x2F;EdDSA key: Sign Authenticate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Current allowed actions: Sign&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (S) Toggle the sign capability&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (A) Toggle the authenticate capability&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (Q) Finished&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Your selection? A&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Possible actions for a ECDSA&#x2F;EdDSA key: Sign Authenticate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Current allowed actions: Sign Authenticate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (S) Toggle the sign capability&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (A) Toggle the authenticate capability&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (Q) Finished&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Your selection? S&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Possible actions for a ECDSA&#x2F;EdDSA key: Sign Authenticate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Current allowed actions: Authenticate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (S) Toggle the sign capability&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (A) Toggle the authenticate capability&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (Q) Finished&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Your selection? Q&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Please select which elliptic curve you want:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (1) Curve 25519&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (3) NIST P-256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (4) NIST P-384&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (5) NIST P-521&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (6) Brainpool P-256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (7) Brainpool P-384&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (8) Brainpool P-512&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (9) secp256k1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Your selection? 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The sub-keys would not be eternal. In my setup, I would consider that an authentication key (which you can use if you wire up your GPG agent to serve as an SSH authentication again, something I may spend another blog post explaining) can be replaced every couple years, for example. So I would say that it should expire in two years. Of course, set your own limit based on your threat model and infrastructure.&lt;&#x2F;p&gt;
&lt;p&gt;All other sub-keys would tend to last longer. In my setup, Signing and Encryption keys last 5 years. That is a long time, but, again, not a lot of people are interesting in busting up my stuff.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Please specify how long the key should be valid.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;         0 = key does not expire&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;n&amp;gt;  = key expires in n days&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;n&amp;gt;w = key expires in n weeks&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;n&amp;gt;m = key expires in n months&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;n&amp;gt;y = key expires in n years&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Key is valid for? (0) 2y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Key expires at Tue 01 Apr 2025 01:55:05 CEST&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Is this correct? (y&#x2F;N) y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Really create? (y&#x2F;N) y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;Contemplating_the_Result&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Contemplating_the_Result&quot; aria-label=&quot;Anchor link for: Contemplating_the_Result&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Contemplating the Result&lt;&#x2F;h2&gt;
&lt;p&gt;With all of the sub-keys created, you should have something like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub   ed25519 2023-03-12 [C]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;lt;ID&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;uid           [ultimate] Lux A. Phifollen (Limefox) &amp;lt;contact@vulpinecitrus.info&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sub   ed25519 2023-03-19 [S] [expires: 2028-03-17]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sub   cv25519 2023-03-19 [E] [expires: 2028-03-17]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sub   ed25519 2023-03-19 [A] [expires: 2025-03-18]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, when you need to provide a key for signature and such, you can provide the main ID of the key. &lt;code&gt;gpg&lt;&#x2F;code&gt; will look into the key and find the first sub-key that is capable of performing the operation you want from it (signing, encrypting; authentication is different but that is another blog post for later).&lt;&#x2F;p&gt;
&lt;p&gt;If you happen to have multiple valid sub-keys that perform the same operation at some point, you can disambiguate which one should be used by providing the &lt;em&gt;key-grip&lt;&#x2F;em&gt; (identifier) of the individual sub-key, and not the main key. You can obtain it by listing the keys with &lt;code&gt;--with-keygrip&lt;&#x2F;code&gt; in your options.&lt;&#x2F;p&gt;
&lt;p&gt;And that’s it! You can honestly use this key pretty much the way you would use any other. It just feels more convenient, because it completely separates all of the operations you can use it for, giving you both the security that your identity is valid as long as your key is secure, the freedom to renew&#x2F;destroy individual components, and the comfort of not having to renew your key (until you accidentally publish the private key&#x2F;password somewhere, for example).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;A_Small_Addendum&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#A_Small_Addendum&quot; aria-label=&quot;Anchor link for: A_Small_Addendum&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
A Small Addendum&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;But, wait, why are neither of your keys like that-&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Shush. I know. It’s not even “do as I say, not as I do”, it is legitimately just that I generated &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;vulpinecitrus.info&#x2F;Lymkwi.gpg.txt&quot;&gt;both of&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;vulpinecitrus.info&#x2F;Limefox.gpg.txt&quot;&gt;my keys&lt;&#x2F;a&gt; a while back, before I knew as much about &lt;code&gt;gpg&lt;&#x2F;code&gt;&#x2F;PGP as I do now. They are, in fact, more of a legacy from a period where I mostly ““needed”“ (with &lt;strong&gt;very&lt;&#x2F;strong&gt; heavy quotes) them to sign commits on Gitlab&#x2F;GitHub. Some day, I will officially retire them and start using a new one, that I already generated with this new methodology. I just have to figure out a couple things regarding user IDs (&lt;code&gt;uid&lt;&#x2F;code&gt;s). As it turns out, it’s useful at times to have your professional identity untied from the fact you’re pretending to be a green anthropomorphic fox on the internet.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>VulpineCitrus is Changing CMS</title>
        <published>2022-12-21T00:00:00+00:00</published>
        <updated>2022-12-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/vulpinecitrus-is-changing-cms/"/>
        <id>https://vulpinecitrus.info/blog/vulpinecitrus-is-changing-cms/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/vulpinecitrus-is-changing-cms/">&lt;p&gt;After 3 years of using &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;hexo.io&#x2F;&quot;&gt;Hexo&lt;&#x2F;a&gt; as my Content Management System for VulpineCitrus, I have finally decided to adopt a more complex system.&lt;&#x2F;p&gt;
&lt;p&gt;I have been looking for decent CMS software for two years, as Hexo had become more of a technical debt than a software I could realistically keep maintaining in shape. Its theme was rewritten by me, and I had received no update to the software since 2019.&lt;&#x2F;p&gt;
&lt;p&gt;While it rendered the entire website into static files based purely on Markdown files, Hexo was getting increasingly abandoned. Furthermore, the nature of its edition meant I could not have a good-looking web interface to edit new pages as I pleased, instead relying on the tedious process of writing a blog post on my local machine running a debug server.&lt;&#x2F;p&gt;
&lt;p&gt;During my investigation I found &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;getgrav.org&quot;&gt;Grav&lt;&#x2F;a&gt;, which seemed okay: it stores your site as flat markdown files, does not have ridiculously complicated features, and, while it runs on PHP7 at the moment, the developers also seem to take the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;getgrav&#x2F;grav&#x2F;security&#x2F;advisories&quot;&gt;security&lt;&#x2F;a&gt; of their software &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;learn.getgrav.org&#x2F;17&#x2F;security&#x2F;overview&quot;&gt;very seriously&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Transferring the old blog posts was okay. I took the freedom to edit some old dead links and fix a few issues here and there. Since Grav also uses Markdown files, I could import &lt;em&gt;most&lt;&#x2F;em&gt; of the blog posts. In some of them however, I used Hexo’s ridiculously convoluted &lt;code&gt;{% %}&lt;&#x2F;code&gt; block syntax.&lt;&#x2F;p&gt;
&lt;p&gt;As of the writing of this, I haven’t yet the reverse proxy of my VPS to point to this site, so it’s going to be a slow process. I might not even reverse-proxy it, since Grav does not stray far from the Nginx root directory it’s confined to, making it less of a pain to deploy. I do not know either whether the theme for this blog will remain the same. At the moment, I’m still testing things out.&lt;&#x2F;p&gt;
&lt;p&gt;Only time can tell.&lt;&#x2F;p&gt;
&lt;p&gt;And one last time, for the memories: the old VulpineCitrus theme.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;vulpinecitrus.info&#x2F;blog&#x2F;vulpinecitrus-is-changing-cms&#x2F;old-vulpinecitrus.png&quot; title=&quot;old-vulpinecitrus&quot; alt=&quot;old-vulpinecitrus&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Hacking Linux: The TCP Stack and Initial Acknowledgement Number</title>
        <published>2022-10-15T00:00:00+00:00</published>
        <updated>2022-10-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/hacking-linux-the-tcp-stack-and-initial-acknowledgement-number/"/>
        <id>https://vulpinecitrus.info/blog/hacking-linux-the-tcp-stack-and-initial-acknowledgement-number/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/hacking-linux-the-tcp-stack-and-initial-acknowledgement-number/">&lt;p&gt;I like messing things up in networks. Sending weird packets into the wild and seeing what happens is quite funny, especially when something breaks, but, sometimes even, when nothing does. I like hacking in the primary sense of the word: messing around and using stuff that was not intended for that purpose.&lt;&#x2F;p&gt;
&lt;p&gt;For a paper I was writing, I had to perform a simple packet analysis of a TCP conversation between a Linux client and a Linux server. I had to detail the way TCP uses sequence and acknowledgement numbers to make the transmission of data reliable. This exercise reminded me of a little fact I had noticed in the past but never really paid attention to: &lt;em&gt;the first packet of a TCP conversation, if sent by a Linux host, will have an acknowledgement number of 0&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This was somewhat unsurprising at first, and I remember noticing it in the past and never really minding it. After all, that number is completely discarded by the client once they receive the server’s acknowledgement number. I had always thought that perhaps, somewhere in the kernel source code, a structure for the TCP header was initialized with zeroes, and simply used to write the packet, and the word of data used for the acknowledgement number remained at zero.&lt;&#x2F;p&gt;
&lt;p&gt;The paper I was writing had to be quite detailed, per the professor’s instructions. I decided to be a pain, and go absolutely too far in my explanations of why the first acknowledgement number sent by Linux is zero. As it turns out, the answer is not that hard, fairly easy to find, but it leads to very funny modifications that you may do if you feel like running a custom kernel.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Finding_the_Acknowledgement_Number&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Finding_the_Acknowledgement_Number&quot; aria-label=&quot;Anchor link for: Finding_the_Acknowledgement_Number&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Finding the Acknowledgement Number&lt;&#x2F;h2&gt;
&lt;p&gt;At first, I wanted to find where that ACK number was initialized. I had two theories:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;There is a structure somewhere that is null-initialized&lt;&#x2F;li&gt;
&lt;li&gt;There is a memory area created that is null-initialized&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;My initial investigation focused on the latter theory for way too long, completely missing the actual answer. After a while, I got there, using the first theory. For the sake of brevity, and because I want to focus this post on the stack itself, I chose not to do a complete addendum on the kernel’s memory allocation mechanism, and only focus on what I found after I had figured out the right track.&lt;&#x2F;p&gt;
&lt;p&gt;For investigating kernel code, I will pull example code from the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;?h=v6.0&quot;&gt;6.0 release tag&lt;&#x2F;a&gt; of the Linux source code on Kernel dot org’s Git repository website. However, all of my actual investigation took place on the wonderful &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&quot;&gt;Bootlin Linux Source Code Cross Referencer&lt;&#x2F;a&gt;, targeting specifically the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.0&#x2F;source&quot;&gt;6.0 tag&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Knowing_Where_to_Look&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Knowing_Where_to_Look&quot; aria-label=&quot;Anchor link for: Knowing_Where_to_Look&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Knowing Where to Look&lt;&#x2F;h2&gt;
&lt;p&gt;I have at this point a bit of familiarity with code in the Linux kernel git tree, at least enough that I know where to look for something. If it’s a device driver for something non-specific (unlike NICs), look in &lt;code&gt;drivers&lt;&#x2F;code&gt;. If it’s about the filesystem, see &lt;code&gt;fs&lt;&#x2F;code&gt;. For networking, it’s in &lt;code&gt;net&lt;&#x2F;code&gt;. It’s not rocket science.&lt;&#x2F;p&gt;
&lt;p&gt;Inside of &lt;code&gt;net&lt;&#x2F;code&gt; however you have distinct bits of code that do different things. Parts of it handles drivers for network devices (ethernet, network cards, WiFi, WWAN, SFP-based cards, etc), others handle the core generic network stack, or the &lt;code&gt;ipv4&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;ipv6&lt;&#x2F;code&gt; bits. It can get fuzzy at this point, but I have a good instinct regarding where to start at that point: &lt;code&gt;struct tcphdr&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In the past I have messed around with TCP in Linux (specifically in XDP). I know the main protocol header structures fairly well (and, sadly, even &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;include&#x2F;linux&#x2F;if_vlan.h?h=v6.0#n30&quot;&gt;those very useful ones&lt;&#x2F;a&gt; that are not exported in the UAPI), and one of them that is very useful in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;include&#x2F;uapi&#x2F;linux&#x2F;tcp.h?h=v6.0#n25&quot;&gt;&lt;code&gt;struct tcphdr&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. I am therefore expecting it to be used and re-used throughout other parts of the Linux kernel, including whatever bit of the network stack that handles writing of the initial TCP packet. Searching on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.0&#x2F;A&#x2F;ident&#x2F;tcphdr&quot;&gt;bootlin&lt;&#x2F;a&gt; shows me a lot of places to look through. I can categorize them thusly:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Files in &lt;code&gt;drivers&lt;&#x2F;code&gt; contains code that may handle parsing of the TCP header of incoming or outbound packets for various purposes (checksum offload&#x2F;verification, for example)&lt;&#x2F;li&gt;
&lt;li&gt;Files in &lt;code&gt;include&lt;&#x2F;code&gt; are mostly headers with other structures that contain&#x2F;mention a &lt;code&gt;struct tcphdr&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Files in &lt;code&gt;net&#x2F;core&lt;&#x2F;code&gt; and &lt;code&gt;net&#x2F;ipv4&lt;&#x2F;code&gt; or &lt;code&gt;net&#x2F;ipv6&lt;&#x2F;code&gt; should be the ones I am looking for, as I expect the behaviour of the first ACK number to be generic across devices&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The rest (&lt;code&gt;tools&lt;&#x2F;code&gt;, &lt;code&gt;samples&lt;&#x2F;code&gt;, &lt;code&gt;net&#x2F;netfilter&lt;&#x2F;code&gt; and such) should not be interesting here.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;The_TCP_Files&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#The_TCP_Files&quot; aria-label=&quot;Anchor link for: The_TCP_Files&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
The TCP Files&lt;&#x2F;h3&gt;
&lt;p&gt;I first looked into the files for TCP IPv4, in &lt;code&gt;net&#x2F;ipv4&lt;&#x2F;code&gt;. I have previously found that some features that are implemented for both versions of IP in use sometimes rely on the same backing code that is in &lt;code&gt;net&#x2F;ipv4&lt;&#x2F;code&gt;. That was the case for &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;&#x2F;net&#x2F;ipv6&#x2F;tcp_ipv6.c?h=v6.0#n1139&quot;&gt;&lt;code&gt;tcp_v6_get_syncookie&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, which, similarly to its IPv4 counterpart, uses &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;net&#x2F;ipv4&#x2F;tcp_input.c?h=v6.0#n6871&quot;&gt;&lt;code&gt;tcp_get_syncookie_mss&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; that is defined in &lt;code&gt;net&#x2F;ipv4&#x2F;tcp_input.c&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Speaking of these TCP files as well, we can see a few of them in &lt;code&gt;net&#x2F;ipv4&lt;&#x2F;code&gt;, notably &lt;code&gt;net&#x2F;ipv4&#x2F;tcp_input.c&lt;&#x2F;code&gt;, &lt;code&gt;net&#x2F;ipv4&#x2F;tcp.c&lt;&#x2F;code&gt; and &lt;code&gt;net&#x2F;ipv4&#x2F;tcp_output.c&lt;&#x2F;code&gt;. Many other files exist, some for the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;net&#x2F;ipv4&#x2F;tcp_cubic.c?h=v6.0&quot;&gt;different&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;net&#x2F;ipv4&#x2F;tcp_vegas.c?h=v6.0&quot;&gt;congestion control&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;net&#x2F;ipv4&#x2F;tcp_nv.c?h=v6.0&quot;&gt;algorithms&lt;&#x2F;a&gt; of TCP, some for &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;net&#x2F;ipv4&#x2F;tcp_bpf.c?h=v6.0&quot;&gt;Berkley Packet Filtering Features&lt;&#x2F;a&gt;, or other &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;net&#x2F;ipv4&#x2F;tcp_fastopen.c?h=v6.0&quot;&gt;weird features&lt;&#x2F;a&gt; of TCP.&lt;&#x2F;p&gt;
&lt;p&gt;“But since that number should be chosen for an outbound packet..”, I thought, “.. maybe I should look in &lt;code&gt;tcp_output.c&lt;&#x2F;code&gt;.”&lt;&#x2F;p&gt;
&lt;h3 id=&quot;TCP_Output_and_SKB_misadventures&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#TCP_Output_and_SKB_misadventures&quot; aria-label=&quot;Anchor link for: TCP_Output_and_SKB_misadventures&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
TCP Output and SKB misadventures&lt;&#x2F;h3&gt;
&lt;p&gt;Inside of TCP output I find where that &lt;code&gt;struct tcphdr&lt;&#x2F;code&gt; is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;net&#x2F;ipv4&#x2F;tcp_output.c?h=v6.0#n1248&quot;&gt;used&lt;&#x2F;a&gt; inside &lt;code&gt;__tcp_transmit_skb&lt;&#x2F;code&gt;, a function that seems to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;net&#x2F;ipv4&#x2F;tcp_output.c?h=v6.0#n1323&quot;&gt;write data&lt;&#x2F;a&gt; from a socket buffer (SKB) to a &lt;code&gt;struct tcphdr&lt;&#x2F;code&gt;. Notably, it sets the &lt;code&gt;ack_seq&lt;&#x2F;code&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;net&#x2F;ipv4&#x2F;tcp_output.c?h=v6.0#n1328&quot;&gt;field of that structure&lt;&#x2F;a&gt; to a parameter &lt;code&gt;rcv_nxt&lt;&#x2F;code&gt; that is passed as a function argument (after setting the correct endianness of course). This is the only place in that file where the &lt;code&gt;ack_seq&lt;&#x2F;code&gt; field, which contains the acknowledgement number of the TCP packet which header is contained in the structure, is being changed, outside of an instance in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;net&#x2F;ipv4&#x2F;tcp_output.c?h=v6.0#n3506&quot;&gt;&lt;code&gt;tcp_make_synack&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. That function name is fairly obvious, and we are not interested in that one.&lt;&#x2F;p&gt;
&lt;p&gt;Climbing up from &lt;code&gt;__tcp_transmit_skb&lt;&#x2F;code&gt; we try and find what calls it. One of the only &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.0&#x2F;A&#x2F;ident&#x2F;__tcp_transmit_skb&quot;&gt;two&lt;&#x2F;a&gt; functions that do (which are both in &lt;code&gt;net&#x2F;ipv4&#x2F;tcp_output.c&lt;&#x2F;code&gt;, again) will also let me explain why the function name &lt;code&gt;__tcp_transmit_skb&lt;&#x2F;code&gt; had me thinking I was on the right track immediately.&lt;&#x2F;p&gt;
&lt;p&gt;This is &lt;code&gt;tcp_transmit_skb&lt;&#x2F;code&gt;, from &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;net&#x2F;ipv4&#x2F;tcp_output.c?h=v6.0#n1417&quot;&gt;&lt;code&gt;net&#x2F;ipv4&#x2F;tcp_output.c&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;static int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; tcp_transmit_skb&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; sock &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;sk&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span&gt; sk_buff &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;skb&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; clone_it&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;			    gfp_t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; gfp_mask&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;	return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; __tcp_transmit_skb&lt;&#x2F;span&gt;&lt;span&gt;(sk, skb, clone_it, gfp_mask,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;				  tcp_sk&lt;&#x2F;span&gt;&lt;span&gt;(sk)-&amp;gt;rcv_nxt);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It’s a wrapper. One that extracts a value from something called &lt;code&gt;sk&lt;&#x2F;code&gt;, and passes it to &lt;code&gt;__tcp_transmit_skb&lt;&#x2F;code&gt; along with the other arguments. Yet, what is an SKB?&lt;&#x2F;p&gt;
&lt;p&gt;SKB, or socket buffer, to make things very simple, is a data structure that keeps track of connection information and data. Its colleague the &lt;code&gt;sock&lt;&#x2F;code&gt; structure is a very generic, and purposely opaque data type which is means to contain information generic enough that it can fit about any network connection in the Linux kernel. Yet, whenever you want to obtain more information, that structure lets you do what helps C bypass the absence of generics: casting.&lt;&#x2F;p&gt;
&lt;p&gt;Calling &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;include&#x2F;linux&#x2F;tcp.h?h=v6.0#n468&quot;&gt;&lt;code&gt;tcp_sk&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; simply means force-casting the &lt;code&gt;sock&lt;&#x2F;code&gt; structure pointer to a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;include&#x2F;linux&#x2F;tcp.h?h=v6.0#n175&quot;&gt;&lt;code&gt;tcp_sock&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; structure pointer. This basically tells the compiler “it’s okay, from now on, handle this as though it was pointing to this structure”. That way, in parts where the connection socket must be handled in a generic manner for multiple protocols, you can keep using a &lt;code&gt;struct sock*&lt;&#x2F;code&gt;, and you can specialize it for parts where you need more specific information (like when you are using TCP).&lt;&#x2F;p&gt;
&lt;p&gt;The force-cast is the followed by a dereferencing read of the field &lt;code&gt;rcv_nxt&lt;&#x2F;code&gt; of &lt;code&gt;struct tcp_sock&lt;&#x2F;code&gt;, which seemingly contains the acknowledgement number to be sent. It makes sense then that when specializing our socket structure we look for that field, and it is later used as the TCP acknowledgement number in all packets, including the first one.&lt;&#x2F;p&gt;
&lt;p&gt;So, what exactly calls &lt;code&gt;tcp_transmit_skb&lt;&#x2F;code&gt;? Well, it is referenced &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;elixir.bootlin.com&#x2F;linux&#x2F;v6.0&#x2F;C&#x2F;ident&#x2F;tcp_transmit_skb&quot;&gt;11 times&lt;&#x2F;a&gt; in &lt;code&gt;net&#x2F;ipv4&#x2F;tcp_output.c&lt;&#x2F;code&gt;. I sift through those, and eventually find &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;net&#x2F;ipv4&#x2F;tcp_output.c?h=v6.0#n3832&quot;&gt;&lt;code&gt;tcp_connect&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, which is helpfully prefaced with the commend &lt;code&gt;&#x2F;* Build a SYN and send it off &#x2F;*&lt;&#x2F;code&gt;. At that point, I knew I was in the right function.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;tcp_connect&lt;&#x2F;code&gt; does a couple big things before calling &lt;code&gt;tcp_transmit_skb&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;It calls the eBPF hook for a TCP socket being opened&lt;&#x2F;li&gt;
&lt;li&gt;It initializes the &lt;code&gt;sock&lt;&#x2F;code&gt; structure later passed on to &lt;code&gt;tcp_transmit_skb&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;It allocates memory for that socket’s buffer (this is where I first lost myself for way too long thinking the null ACK came from a null initialized buffer)&lt;&#x2F;li&gt;
&lt;li&gt;It performs a couple of checks additional checks (notably &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;net&#x2F;ipv4&#x2F;tcp_output.c?h=v6.0#n319&quot;&gt;explicit congestion notice&lt;&#x2F;a&gt; initialization)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Let us focus on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;net&#x2F;ipv4&#x2F;tcp_output.c?h=v6.0#n3645&quot;&gt;&lt;code&gt;tcp_connect_init&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, which sets up all the information possible for the socket that is independent of its address family. Within that method, we also force-cast the socket &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;net&#x2F;ipv4&#x2F;tcp_output.c?h=v6.0#n3649&quot;&gt;early on&lt;&#x2F;a&gt; into a &lt;code&gt;struct tcp_sock&lt;&#x2F;code&gt;, which is used for the rest of the function. Looking at the rest of the code, it’s a lot of function setup, and field initialization. One field in particular rings a bell.&lt;&#x2F;p&gt;
&lt;p&gt;Around the end of the function, protected by an if (related to a thing called TCP connection repair where a TCP connection is re-established on a new host as though it was continued from another host, which I’m not going to go on about), we find the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;net&#x2F;ipv4&#x2F;tcp_output.c?h=v6.0#n3711&quot;&gt;initialization of &lt;code&gt;rcv_nxt&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, to the value &lt;code&gt;0&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Interestingly, that precise line of code hasn’t changed in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;torvalds&#x2F;linux&#x2F;blame&#x2F;master&#x2F;net&#x2F;ipv4&#x2F;tcp_output.c#L3716&quot;&gt;11 years&lt;&#x2F;a&gt;, so chances are the choice to use &lt;code&gt;0&lt;&#x2F;code&gt; for the first acknowledgement number is quite old.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Exploiting_that_Knowledge:_A_Custom_Initial_TCP_ACK_Number&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Exploiting_that_Knowledge:_A_Custom_Initial_TCP_ACK_Number&quot; aria-label=&quot;Anchor link for: Exploiting_that_Knowledge:_A_Custom_Initial_TCP_ACK_Number&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Exploiting that Knowledge: A Custom Initial TCP ACK Number&lt;&#x2F;h2&gt;
&lt;p&gt;At first, I wrote my paper and kept this funny paragraph that went on a really deep tangent about the ACK number. I left it simmer in my head until a couple weeks later when a horrible intrusive thought suddenly struck me as I was compiling my &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Lymkwi&#x2F;linux&quot;&gt;own frankenstein kernel&lt;&#x2F;a&gt; mangled from the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Rust-for-Linux&#x2F;linux&quot;&gt;Rust for Linux&lt;&#x2F;a&gt; kernel (which I will talk about for a later post) and my own changes.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;What if I changed the ACK number?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I sat in horror and thought to myself that surely something else in the stack of the kernel would prevent me from doing that. It’s a terrible idea from a privacy standpoint, since that would mark a packet circulating on the internet as &lt;em&gt;exclusively&lt;&#x2F;em&gt; coming from &lt;em&gt;precisely&lt;&#x2F;em&gt; my laptop. And yet, why not try?&lt;&#x2F;p&gt;
&lt;p&gt;I sat home that day and opened the source code I was compiling earlier, went into &lt;code&gt;net&#x2F;ipv4&#x2F;tcp_output.c&lt;&#x2F;code&gt; and edited the precise line I mentioned above. I thought to myself, “I’m doing something stupid, why not make it even worse”, and thought about a string of characters I could put. Originally, I went with &lt;code&gt;:3&lt;&#x2F;code&gt; (two bytes, &lt;code&gt;0x3a33&lt;&#x2F;code&gt;). I later settled with &lt;code&gt;OwO!&lt;&#x2F;code&gt; (4 bytes, &lt;code&gt;0x4f774f21&lt;&#x2F;code&gt;). I wrote that value, recompiled, installed, and rebooted.&lt;&#x2F;p&gt;
&lt;p&gt;To my shock and horror, my first explicit TCP query once I had a terminal worked. Worse even, everything else that had been launched by default worked. All my TCP connections worked. I opened a shell, ran &lt;code&gt;tcpdump&lt;&#x2F;code&gt;, filtered for &lt;code&gt;tcp[13] &amp;amp; 0x12 == 0x02&lt;&#x2F;code&gt; (searching for TCP packets with ACK off and SYN on), and had the biggest bout of laughter in recent memories when I read &lt;code&gt;OwO!&lt;&#x2F;code&gt; in my packets.&lt;&#x2F;p&gt;
&lt;p&gt;It worked. It just worked. Apparently I hadn’t broken anything. No kernel errors in &lt;code&gt;dmesg&lt;&#x2F;code&gt;. No idea if specific, weird situations were broken. My assumption that something could have broken because I was suddenly not using &lt;code&gt;0&lt;&#x2F;code&gt; was seemingly wrong, and I got to make myself and a couple of my friends laugh when I showed them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Where_to_Go_From_Here?&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Where_to_Go_From_Here?&quot; aria-label=&quot;Anchor link for: Where_to_Go_From_Here?&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Where to Go From Here?&lt;&#x2F;h2&gt;
&lt;p&gt;Talking with my friends, I discussed a couple of funny things I could do to hack my kernel further. I have always been fascinated by the interface exposed through &lt;code&gt;&#x2F;proc&lt;&#x2F;code&gt; that lets you configure kernel features dynamically from the filesystem, and I think I want to try and expose a custom endpoint &lt;code&gt;&#x2F;proc&#x2F;sys&#x2F;net&#x2F;ipv4&#x2F;tcp_initial_ack_number&lt;&#x2F;code&gt; where I can write whatever stuff that I want to use for that number, and have Linux use it.&lt;&#x2F;p&gt;
&lt;p&gt;I also thought about the privacy aspects of using &lt;code&gt;0&lt;&#x2F;code&gt;. Since seemingly every Linux machine does, that protects us all in a way by making our connections impossible to fingerprint using that field. Me using a custom value completely undoes that, and makes me exactly identifiable, even through things like NAT. I thought about going a step further from a custom value, to a random one. Maybe I should work a little eBPF&#x2F;XDP program I can hook on my RPI 4 home router that takes all of the incoming TCP packets that are purely SYN and randomizes their ACK number before forwarding? That could be interesting.&lt;&#x2F;p&gt;
&lt;p&gt;There is a lot of ways I could further this, and lots of cool hacking stuff to do with the Linux kernel and its networking stack.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Clippy: Obey the Paperclip</title>
        <published>2022-09-28T00:00:00+00:00</published>
        <updated>2022-09-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/clippy-obey-the-paperclip/"/>
        <id>https://vulpinecitrus.info/blog/clippy-obey-the-paperclip/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/clippy-obey-the-paperclip/">&lt;p&gt;I have been using Rust on and off for the past five years or so, first picking it up around the time release 1.0 dropped. I then seriously learned the language in 2019, and, thanks to coding events such as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;adventofcode.com&#x2F;&quot;&gt;Advent of Code&lt;&#x2F;a&gt;, found a reason to make (arguably) &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Lymkwi&#x2F;AdventOfCode-2020&quot;&gt;beautiful&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;Lymkwi&#x2F;AdventOfCode-2021&quot;&gt;code&lt;&#x2F;a&gt; that trained me to make simple data structures work efficiently together to solve problems. Nowadays, I scale my development towards multi-threaded, asynchronous programs, in particular web server &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;Lymkwi&#x2F;oxbox&#x2F;&quot;&gt;toys&lt;&#x2F;a&gt; and active projects (to be announced soon).&lt;&#x2F;p&gt;
&lt;p&gt;My workflow in Rust has increasingly involved a tool that my peers find funny (for good reasons), and which has helped me tremendously when it came to writing Rust that works but also &lt;em&gt;works well&lt;&#x2F;em&gt; and is pleasant to read: &lt;strong&gt;pain&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Clippy&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Clippy&quot; aria-label=&quot;Anchor link for: Clippy&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Clippy&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust-clippy&quot;&gt;Clippy&lt;&#x2F;a&gt; is Rust’s official linter program to “catch common mistakes and improve your Rust code”. Rust is, contrary to what people feel, extremely friendly towards new developers: the compiler spits out nice error messages with suggestions for fixes that are almost always right, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;book&#x2F;&quot;&gt;the Book&lt;&#x2F;a&gt; is the greatest piece of documentation I have ever read, the community of developers is extremely friendly and ready to explain concepts that are indeed hard to grasp for a lot of developers at first, etc.&lt;&#x2F;p&gt;
&lt;p&gt;Clippy can be installed into &lt;code&gt;cargo&lt;&#x2F;code&gt;, Rust’s project management tool, using the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;rustup.rs&#x2F;&quot;&gt;rustup&lt;&#x2F;a&gt; toolchain manager. It integrates perfectly in the environment of other tools cargo provides, and it can be integrated in your linting routine to show you common mistakes.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;The_Lint_Groups&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#The_Lint_Groups&quot; aria-label=&quot;Anchor link for: The_Lint_Groups&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
The Lint Groups&lt;&#x2F;h3&gt;
&lt;p&gt;Clippy groups its linting rules into groups, or categories that you can &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;rust-lang.github.io&#x2F;rust-clippy&#x2F;stable&#x2F;&quot;&gt;find on their search engine&lt;&#x2F;a&gt; and allow&#x2F;deny&#x2F;warn as a whole. The most notable groups are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;complexity&lt;&#x2F;strong&gt;: catches common errors that make your code needlessly complex for tasks that you are trying to make&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;correctness&lt;&#x2F;strong&gt;: catches code that is grammatically correct but results in nonsensical, typically unintended actions&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;deprecated&lt;&#x2F;strong&gt;: catches usage of deprecated methods&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;nursery&lt;&#x2F;strong&gt;: catches errors newcomers to Rust often make&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;pedantic&lt;&#x2F;strong&gt;: catches common errors that developers who are more familiar with Rust make that could be turned into better code&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;perf&lt;&#x2F;strong&gt;: catches resource-wasting patterns (creating default objects ahead, etc)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;suspicious&lt;&#x2F;strong&gt;: catches code that looks suspiciously like the first step towards a bug or bad manipulation of the code base&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Other categories exist, but these are the ones I think about the most. Another one I have to mention is &lt;strong&gt;restriction&lt;&#x2F;strong&gt;, which is hilarious to me. It is meant to restrict usage of patterns forbidden for a specific project (either because of style policies, or constraints). In fact, it is so thorough and unforgiving that you literally &lt;em&gt;cannot&lt;&#x2F;em&gt; act on it as a whole, since some of the lints in there are &lt;em&gt;contradictory&lt;&#x2F;em&gt; (see the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;rust-lang.github.io&#x2F;rust-clippy&#x2F;master&#x2F;#inline_asm_x86_intel_syntax&quot;&gt;AT&amp;amp;T&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;rust-lang.github.io&#x2F;rust-clippy&#x2F;master&#x2F;#inline_asm_x86_intel_syntax&quot;&gt;Intel&lt;&#x2F;a&gt; asm flavour lints, for example).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Pain&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Pain&quot; aria-label=&quot;Anchor link for: Pain&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Pain&lt;&#x2F;h2&gt;
&lt;p&gt;The seven groups I mentioned above, along with &lt;code&gt;clippy::style&lt;&#x2F;code&gt; and &lt;code&gt;clippy::cargo&lt;&#x2F;code&gt;, are &lt;em&gt;completely denied&lt;&#x2F;em&gt; in most, if not all of my projects. They will typically also include more lints from standard Rust. As of the writing of this post, my linting header is as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; Make clippy quite nasty&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#![deny(clippy&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;cargo)]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;			&#x2F;&#x2F; Checks for garbage in the Cargo TOML files&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#![deny(clippy&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;complexity)]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;	&#x2F;&#x2F; Checks for needlessly complex structures&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#![deny(clippy&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;correctness)]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;	&#x2F;&#x2F; Checks for common invalid usage and workarounds&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#![deny(clippy&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;nursery)]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;		&#x2F;&#x2F; Checks for things that are typically forgotten by learners&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#![deny(clippy&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;pedantic)]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;		&#x2F;&#x2F; Checks for mildly annoying comments it could make about your code&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#![deny(clippy&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;perf)]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;			&#x2F;&#x2F; Checks for inefficient ways to perform common tasks&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#![deny(clippy&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;style)]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;			&#x2F;&#x2F; Checks for inefficient styling of code&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#![deny(clippy&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;suspicious)]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;	&#x2F;&#x2F; Checks for potentially malicious behaviour&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; Add some new clippy lints&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#![deny(clippy&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;use_self)]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;		&#x2F;&#x2F; Checks for the use of a struct&amp;#39;s name in its `impl`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; Add some default lints&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#![warn(unused_variables)]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;		&#x2F;&#x2F; Checks for unused variables&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; Deny missing documentation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#![deny(missing_docs)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#![deny(rustdoc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;missing_crate_level_docs)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is pain incarnate. People I talk with who are starting out in Rust would rather bang their head against a wall than try and satisfy such draconian requirements. By all means, I tell them, they could be &lt;em&gt;far worse&lt;&#x2F;em&gt;!&lt;&#x2F;p&gt;
&lt;p&gt;Yet this approach forces you to write code that is not only &lt;em&gt;valid&lt;&#x2F;em&gt;, and &lt;em&gt;correct&lt;&#x2F;em&gt;, but good. I started out simply denying &lt;code&gt;clippy::pedantic&lt;&#x2F;code&gt;, which is enough to get a good grasp of good practices in Rust. Once no lints typically fire after you are finished writing a piece of code, try and deny another category, like &lt;code&gt;nursery&lt;&#x2F;code&gt;. Then, &lt;code&gt;correctness&lt;&#x2F;code&gt;, or &lt;code&gt;perf&lt;&#x2F;code&gt;. After a while, you will learn about the common mistakes you make, and recognize the patterns, and catch yourself in the act, before Clippy can yell at you. After that, learn about the mistakes you do from a new group!&lt;&#x2F;p&gt;
&lt;p&gt;At some point you end up with code that is functional, efficient and good-looking. Rust code already looks beautiful in general, but good Rust code is pleasant to read (especially if you literally force yourself to write good documentation with the documentation lints).&lt;&#x2F;p&gt;
&lt;p&gt;With time, you learn to love that nasty paperclip. 📎&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The Weird Debugging Story of How I Wanted to Create a UEFI VM with Libvirt</title>
        <published>2022-04-12T00:00:00+00:00</published>
        <updated>2022-04-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/the-weird-debugging-story-of-how-i-wanted-to-create-a-uefi-vm-with-libvirt/"/>
        <id>https://vulpinecitrus.info/blog/the-weird-debugging-story-of-how-i-wanted-to-create-a-uefi-vm-with-libvirt/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/the-weird-debugging-story-of-how-i-wanted-to-create-a-uefi-vm-with-libvirt/">&lt;p&gt;This post is mostly a story about my new VM server setup. However, it features a fun twist that reminds me how important it is to consider the layers upon layers of added security tools that exist in Linux that could interfere with a normal setup.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_Context&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#The_Context&quot; aria-label=&quot;Anchor link for: The_Context&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
The Context&lt;&#x2F;h2&gt;
&lt;p&gt;Around a month and a half ago I got this new server in my infrastructure, an old decommissioned &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.dell.com&#x2F;support&#x2F;kbdoc&#x2F;fr-fr&#x2F;000129841&#x2F;precision-t1700-desktop-workstation-hardware-specifications-sp%C3%A9cifications-mat%C3%A9rielles-pour-la-station-de-travail-de-bureau-precision-t1700&quot;&gt;Dell Precision T1700&lt;&#x2F;a&gt;. I was pleasantly surprised to learn that it has an Intel Xeon with 8 cores at 3.5GHz (which makes it the most powerful server I own aside from my main workstation).&lt;&#x2F;p&gt;
&lt;p&gt;I decided to move a couple of services off of my VPS, which had been &lt;em&gt;struggling&lt;&#x2F;em&gt; under the load that Matrix Synapse puts on it. So far, aside from the CPU spending &lt;em&gt;roughly&lt;&#x2F;em&gt; half of its time in I&#x2F;O idle (I never replaced the hard drives in it, they have lived a good life, and I have no irreplaceable data on them, so I’m just waiting for a failure before buying new ones), the server is fine. It is so fine in fact that I wanted to add more onto the pile of things it would have to deal with.&lt;&#x2F;p&gt;
&lt;p&gt;A week or so ago I was doing a lab at school where the teacher provided us with a Virtualbox Appliance VM image so we could have all of the tools and setup for the lab. Since I was running everything on my Thinkpad, which already had libvirt&#x2F;virt-manager installed, I wanted to see if I could &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;edoceo.com&#x2F;notabene&#x2F;ova-to-vmdk-to-qcow2&quot;&gt;convert the OVA into QCow2&lt;&#x2F;a&gt; or better &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;blogs.oracle.com&#x2F;oda&#x2F;post&#x2F;kvm-import-an-ova-template&quot;&gt;import the OVA as a VM&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;A_Tangent_on_OVAs_and_Virt-Manager&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#A_Tangent_on_OVAs_and_Virt-Manager&quot; aria-label=&quot;Anchor link for: A_Tangent_on_OVAs_and_Virt-Manager&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
A Tangent on OVAs and Virt-Manager&lt;&#x2F;h2&gt;
&lt;p&gt;As it turns out, an OVA is simply a TAR archive with three files in it : the disk image, a XML file (something dot ovf) containing the VM settings, and a third on that is optional and which purpose I am not entirely sure of.&lt;&#x2F;p&gt;
&lt;p&gt;Long story short I struggled the entire lab to try and make the VM work on QEMU with Libvirt, but failed. I ended up running VirtualBox for the parts I really needed to get running (I mostly listened to the lab, which was mostly a lesson, but I’m digressing).&lt;&#x2F;p&gt;
&lt;p&gt;See, first of all, Libvirt’s virtual machine assistant has this funny quirk where if you want to change things like the chipset used or the firmware (which defaults to BIOS), you have to specify one little option before creating the VM. Otherwise, it’s set forever (unless you really know what you are doing and love editing XML).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;vulpinecitrus.info&#x2F;blog&#x2F;the-weird-debugging-story-of-how-i-wanted-to-create-a-uefi-vm-with-libvirt&#x2F;libvirt_uefi_config.png&quot; alt=&quot;“I like using Deltarune references for my VMs”&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;During the whole ordeal I figured I could offload the garbage of running libvirt onto a remote server… or my new server.&lt;&#x2F;p&gt;
&lt;p&gt;A couple of SSH tweaks and copying public keys later and I had a connection from my laptop to the libvirt daemon running on my Dell Precision server. It was just the beginning.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#&quot; aria-label=&quot;Anchor link for: &quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
Debugging the Lolipop in the Machine&lt;&#x2F;h2&gt;
&lt;p&gt;You work at a factory. You are in charge of maintenance on a lot of complicated machines with a lot of moving parts. During maintenance for one of the machines, you figure out the issue comes from an authorization module. You bypass the module to let the machine run, but it does not. Fiddling more in the gears, you realize there is a &lt;em&gt;second, separate&lt;&#x2F;em&gt; authorization module with a lolipop stuck in it. That module overrides the first one, and someone probably dropped their lolipop into it. You spent five hours on this, because someone dropped a lolipop on a module you didn’t know existed.&lt;&#x2F;p&gt;
&lt;p&gt;You never expect a lolipop in an industrial machine. Yet, sometimes, you should.&lt;&#x2F;p&gt;
&lt;p&gt;When I tried to create a UEFI machine through Virt-Manager’s wizard, after figuring out I needed to configure before creating, I ran into errors saying that access to the NVRAM variable files for that machine was unauthorized. I was running libvirt as root, and connecting through a user that was in the &lt;code&gt;libvirt&lt;&#x2F;code&gt; group. I figured, which not try and set the permissions for that file to &lt;code&gt;777&lt;&#x2F;code&gt; so I was sure I could find it ? I still hit a “Permission Denied” wall.&lt;&#x2F;p&gt;
&lt;p&gt;After some research online I figured out that &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;bugs.launchpad.net&#x2F;ubuntu&#x2F;+source&#x2F;libvirt&#x2F;+bug&#x2F;1962035&quot;&gt;there is currently a bug&lt;&#x2F;a&gt; in the apparmor profiles brought in alongside Libvirt where the authorizations granted to &lt;code&gt;libvirtd&lt;&#x2F;code&gt; when it starts do not allow it to read &lt;code&gt;&#x2F;var&#x2F;lib&#x2F;libvirt&#x2F;qemu&#x2F;nvram&#x2F;*.fd&lt;&#x2F;code&gt;. The fix that is currently released on Ubuntu (but not even Debian sid yet) only modifies &lt;code&gt;&#x2F;etc&#x2F;apparmor.d&#x2F;abstractions&#x2F;libvirt-qemu&lt;&#x2F;code&gt; to apply this patch&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;diff&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FDAEB7;background-color: #86181D;&quot;&gt;--- &#x2F;etc&#x2F;apparmor.d&#x2F;abstractions&#x2F;libvirt-qemu.orig 2022-01-22&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;time: &amp;#39;18:22:57.000000000 +0000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+++ &#x2F;etc&#x2F;apparmor.d&#x2F;abstractions&#x2F;libvirt-qemu 2022-02-25&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;time: &amp;#39;13:54:22.075405809 +0000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;font-weight: bold;&quot;&gt;@@ -85,7 +85,7 @@&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &#x2F;usr&#x2F;share&#x2F;misc&#x2F;sgabios.bin r,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &#x2F;usr&#x2F;share&#x2F;openbios&#x2F;** r,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &#x2F;usr&#x2F;share&#x2F;openhackware&#x2F;** r,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FDAEB7;background-color: #86181D;&quot;&gt;-  &#x2F;usr&#x2F;share&#x2F;OVMF&#x2F;** r,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+  &#x2F;usr&#x2F;share&#x2F;OVMF&#x2F;** rk,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &#x2F;usr&#x2F;share&#x2F;ovmf&#x2F;** r,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &#x2F;usr&#x2F;share&#x2F;proll&#x2F;** r,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &#x2F;usr&#x2F;share&#x2F;qemu-efi&#x2F;** r,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;font-weight: bold;&quot;&gt;@@ -249,5 +249,8 @@&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &#x2F; r, # harmless on any lsb compliant system&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &#x2F;sys&#x2F;bus&#x2F;nd&#x2F;devices&#x2F;{,**&#x2F;} r,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+  # required for QEMU accessing UEFI nvram variables&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+  &#x2F;**&#x2F;nvram&#x2F;*_VARS.fd rwk,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #85E89D;background-color: #144620;&quot;&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   # Site-specific additions and overrides. See local&#x2F;README for details.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   #include &amp;lt;local&#x2F;abstractions&#x2F;libvirt-qemu&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then you just &lt;code&gt;systemctl restart apparmor&lt;&#x2F;code&gt; and &lt;code&gt;systemctl restart libvirt&lt;&#x2F;code&gt; and you get going.&lt;&#x2F;p&gt;
&lt;p&gt;The funny thing I found out later on is that it’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;bugs.launchpad.net&#x2F;ubuntu&#x2F;+source&#x2F;libvirt&#x2F;+bug&#x2F;1890858&quot;&gt;not the only apparmor-related bug in libvirt&lt;&#x2F;a&gt;, apparently.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;-1&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#-1&quot; aria-label=&quot;Anchor link for: -1&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
The Aftermath&lt;&#x2F;h2&gt;
&lt;p&gt;In the end, I just wanted to use Virt-Manager and make my little toy VM, but I got sidetracked into the depth of libvirt, and its side interactions with Apparmor.
I have managed to install a little remote VM that runs decently and that I hope to turn into my practice VM for things like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;hackthebox.eu&#x2F;&quot;&gt;Hack The Box&lt;&#x2F;a&gt; or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;tryhackme.com&#x2F;&quot;&gt;Try Hack Me&lt;&#x2F;a&gt;. &lt;del&gt;Or, at least, whenever I have time for these again&lt;&#x2F;del&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Advent of Code 2021 - Retrospective</title>
        <published>2022-01-01T00:00:00+00:00</published>
        <updated>2022-01-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/advent-of-code-2021-retrospective/"/>
        <id>https://vulpinecitrus.info/blog/advent-of-code-2021-retrospective/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/advent-of-code-2021-retrospective/">&lt;p&gt;This year, like the last, I participated in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;adventofcode.com&#x2F;&quot;&gt;Advent of Code&lt;&#x2F;a&gt;, an online event where a new algorithmics puzzle is unlocked every day of december before and on the 25th. For each day, the same puzzle idea yields two small exercises, one typically easier than the other.&lt;&#x2F;p&gt;
&lt;p&gt;I chose &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;rust-lang.org&#x2F;&quot;&gt;Rust&lt;&#x2F;a&gt;, like last year, to solve those problems. You can find my repository &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;Lymkwi&#x2F;AdventOfCode-2021&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;A_bit_of_write-up_for_the_days_I_found_interesting&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#A_bit_of_write-up_for_the_days_I_found_interesting&quot; aria-label=&quot;Anchor link for: A_bit_of_write-up_for_the_days_I_found_interesting&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
A bit of write-up for the days I found interesting&lt;&#x2F;h2&gt;
&lt;p&gt;Most puzzles were interesting, to very interesting. The first week or so is easy to solve as long as you have a good handling of simple data structures and logic branching.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;A_word_on_boilerplate&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#A_word_on_boilerplate&quot; aria-label=&quot;Anchor link for: A_word_on_boilerplate&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
A word on boilerplate&lt;&#x2F;h3&gt;
&lt;p&gt;In order to have a faster time coding and testing my code, I spent the first couple days perfecting a boilerplate system, learning about Rust’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;book&#x2F;ch14-03-cargo-workspaces.html&quot;&gt;workspace crate mechanism&lt;&#x2F;a&gt;. The code I wrote was very simple :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A shell day crate that could be copied and which content could be changed to deploy the simple boilerplate code for the day&lt;&#x2F;li&gt;
&lt;li&gt;A benchmarking area&lt;&#x2F;li&gt;
&lt;li&gt;A lot of testing that the code gave the right results for tests and answers&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The shell crates I made had the basic bin&#x2F;lib structure, where all of my logic code resided in methods called &lt;code&gt;solve_part_one&lt;&#x2F;code&gt; and &lt;code&gt;solve_part_two&lt;&#x2F;code&gt; in &lt;code&gt;src&#x2F;lib.rs&lt;&#x2F;code&gt;, which could be imported by the higher-level crate for testing, or &lt;code&gt;src&#x2F;main.rs&lt;&#x2F;code&gt; to be executed &#x2F; test sample inputs.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Day_1_:_Slice_Windows&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Day_1_:_Slice_Windows&quot; aria-label=&quot;Anchor link for: Day_1_:_Slice_Windows&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
Day 1 : Slice Windows&lt;&#x2F;h3&gt;
&lt;p&gt;Day 1 had me a little stumped, but not for any valid reason. I just had never thought about the concept of a &lt;em&gt;window iterator&lt;&#x2F;em&gt; in Rust. I was sure there must have
been something like that in the standard library, I just did not know where. It turns out, the &lt;code&gt;slice&lt;&#x2F;code&gt; primitive type is equipped with a &lt;code&gt;windows&lt;&#x2F;code&gt; method that yields a special iterator over a given amount of elements in the original slice.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Day_5_:_HashMap_is_good_for_grids_(with_moderation)&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Day_5_:_HashMap_is_good_for_grids_(with_moderation)&quot; aria-label=&quot;Anchor link for: Day_5_:_HashMap_is_good_for_grids_(with_moderation)&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
Day 5 : HashMap is good for grids (with moderation)&lt;&#x2F;h3&gt;
&lt;p&gt;Continuing from a theme I had last year, using &lt;code&gt;std::collections::HashMap&lt;&#x2F;code&gt; instead of a fixed size grid can turn out to be a life saving spark of genius if it turns
out your puzzle input is larger than expected, your data is lacunar, or your coordinate space expands to negative coordinates. Last year, the various versions of
Conway’s Game of Life had us play around with multi-dimensional grids that could expand to unreasonable sizes in any direction, and I found that storing one type
of state information as coordinates in a &lt;code&gt;HashMap&lt;&#x2F;code&gt; (or &lt;code&gt;HashSet&lt;&#x2F;code&gt;), and assuming that absence from that structure means another state information, can be fairly useful.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Day_23_:_Hashing_is_good,_with_moderation_(and_well)&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Day_23_:_Hashing_is_good,_with_moderation_(and_well)&quot; aria-label=&quot;Anchor link for: Day_23_:_Hashing_is_good,_with_moderation_(and_well)&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
Day 23 : Hashing is good, with moderation (and well)&lt;&#x2F;h3&gt;
&lt;p&gt;A caveat of the previous point is that hashing still comes at a cost, particularly for complicated data structures that you define yourself. I had an example
in day 23 where I needed to store the states of my puzzle state space that I had already explored in order to avoid needlessly repeating computations, and filling
memory. To do so, I chose to use a &lt;code&gt;HashSet&lt;&#x2F;code&gt; and implemented &lt;code&gt;std::hash::Hash&lt;&#x2F;code&gt; on a type that was essentially an enum and 30-ish integers in a trench coat.&lt;&#x2F;p&gt;
&lt;p&gt;My first implementation iterated all over every single one of these values, and hashed them all individually.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[derive(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Clone&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Copy&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; PartialEq&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Eq&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Debug&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; PartialOrd&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Ord&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Hash&lt;&#x2F;span&gt;&lt;span&gt;)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;enum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Amphipod&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    Amber&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    Bronze&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    Copper&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    Desert&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[derive(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Clone&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Copy&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Debug&lt;&#x2F;span&gt;&lt;span&gt;)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; AmphipodPuzzleState&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    cost&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; usize&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    hallway&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Option&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Amphipod&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 11&lt;&#x2F;span&gt;&lt;span&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    chambers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Option&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Amphipod&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; bool&lt;&#x2F;span&gt;&lt;span&gt;)&amp;gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;];&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    part_one&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; bool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;impl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; std&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;hash&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;Hash&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; for&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; AmphipodPuzzleState&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;	fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; hash&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;H&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Hasher&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, state&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;: &amp;amp;mut&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; H&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;		for&lt;&#x2F;span&gt;&lt;span&gt; potential&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;hallway {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;			if let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; Some&lt;&#x2F;span&gt;&lt;span&gt;(amp)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; potential {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;				&#x2F;&#x2F; Room no yields a number between 0 and 3 depending&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;				&#x2F;&#x2F; on the value of the enum&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;				amp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;room_no&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;hash&lt;&#x2F;span&gt;&lt;span&gt;(state);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; else&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;				(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;hash&lt;&#x2F;span&gt;&lt;span&gt;(state);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;		&#x2F;&#x2F; .. You get the idea&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This was, as I can see now, horrendously slow. Indeed, having to endure the overhead of a single hashing for &lt;strong&gt;every single number&lt;&#x2F;strong&gt; in the structure was
absolutely too much.&lt;&#x2F;p&gt;
&lt;p&gt;A second version of this implementation created a single number by &lt;em&gt;pushing a base 5 number&lt;&#x2F;em&gt; into a number stack and hashing it (you will see that it’s a theme this year). However, that was still quite slow.&lt;&#x2F;p&gt;
&lt;p&gt;In the end, just creating a method that yielded a fixed-length array of numbers that itself could be automatically hashed worked better. The overhead of hashing still slowed down the code, but I managed to get sub-1s in &lt;code&gt;release&lt;&#x2F;code&gt; target.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Day_24_:_Sometimes_it’s_not_about_simulating,_it’s_about_reading_and_counting&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Day_24_:_Sometimes_it’s_not_about_simulating,_it’s_about_reading_and_counting&quot; aria-label=&quot;Anchor link for: Day_24_:_Sometimes_it’s_not_about_simulating,_it’s_about_reading_and_counting&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
Day 24 : Sometimes it’s not about simulating, it’s about reading and counting&lt;&#x2F;h3&gt;
&lt;p&gt;On day 6, we were presented with a problem that seemingly asked us to simulate an unreasonable amount of data. It turns out we only needed to realize that some states were independent of the others, and count.&lt;&#x2F;p&gt;
&lt;p&gt;On day 14, we were once again tricked. The polymerization exercise demanded outright impossible simulation. People who had working short-term memory remembered the lanternfish exercise from a week prior, and simply figured out you could use &lt;em&gt;dynamic programming&lt;&#x2F;em&gt; to cut down on simulation, and count.&lt;&#x2F;p&gt;
&lt;p&gt;On day 24, we were presented with assembly instructions. I spent a lot of time building a robust, modular instruction simulator, confident that we would need to simulate this program.&lt;&#x2F;p&gt;
&lt;p&gt;Nope.&lt;&#x2F;p&gt;
&lt;p&gt;It turns out, and don’t read if you don’t want it spoiled, that the program performed a 14-cycle parametric “hashing” process that essentially pushed and popped a base 26 number (see, I said it would be a theme), computed from a test input and some of the aforementionned parameters. The goal was to get the end value to 0. Solving day 24 required way more &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kemmel-dev&#x2F;AdventOfCode2021&#x2F;blob&#x2F;master&#x2F;day24&#x2F;AoC%20Day%2024.pdf&quot;&gt;program structure analysis&lt;&#x2F;a&gt; than pure programming skill.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Day_22_:_Papers_aren’t_really_always_helpful&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Day_22_:_Papers_aren’t_really_always_helpful&quot; aria-label=&quot;Anchor link for: Day_22_:_Papers_aren’t_really_always_helpful&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
Day 22 : Papers aren’t really always helpful&lt;&#x2F;h3&gt;
&lt;p&gt;I spent a large amount of my time on day 22 trying to see if someone smarter than me had figured out a general algorithm to compute the real volume of a set of
axis-aligned, intersecting cuboids in 3D space. I read a couple brain-melting papers that solved this efficiently for cubes, and more general versions that were
really above my understanding.&lt;&#x2F;p&gt;
&lt;p&gt;I just ended up creating a system where the intersection of an added cuboid was computed against every cuboid already in the set, and the added cuboid was split into
smaller cuboids accordingly in order to shave off and split the added cuboid into a set of smaller, non intersecting cuboids. Computing the difference of volume
and adding them then became trivial.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Binary_optimization_is_madness&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#Binary_optimization_is_madness&quot; aria-label=&quot;Anchor link for: Binary_optimization_is_madness&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
Binary optimization is madness&lt;&#x2F;h3&gt;
&lt;p&gt;The worst runtime I had this year was day 19, before a large optimization I made. In &lt;code&gt;debug&lt;&#x2F;code&gt; target, it ran for about 70 seconds before spitting out the right
answer on my input. However, building in the &lt;code&gt;release&lt;&#x2F;code&gt; target reduced the runtime to a mere &lt;em&gt;&lt;strong&gt;3 and a half seconds&lt;&#x2F;strong&gt;&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;More generally, I have to say that the binary optimization on the &lt;code&gt;release&lt;&#x2F;code&gt; target for Rust is mind-bogglingly fast. Repeated operations seem to fly by like the
compiled itself predicted your data and shrunk the binary to just solve what could change. The world of compiler optimization looks fascinating, and very complex.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;More_general_things_I_learned&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#More_general_things_I_learned&quot; aria-label=&quot;Anchor link for: More_general_things_I_learned&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
More general things I learned&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Rust is very powerful, yet,&lt;&#x2F;li&gt;
&lt;li&gt;Rust is not very well suited for a lot of fast, dirty problem solving.&lt;&#x2F;li&gt;
&lt;li&gt;Zero-cost abstraction is wonderful. I could write entire structures to describe my problems very clearly (like &lt;code&gt;Amphipod&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;AmphipodPuzzleState&lt;&#x2F;code&gt; for day 23, and have close to no overhead from it)&lt;&#x2F;li&gt;
&lt;li&gt;The people who strive for leaderboard on this event are all generally american and do not work a job where they have to wake up early&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;And that’s about all I can come up with for now! I want to thanks &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;was.tl&#x2F;&quot;&gt;Eric Wastl&lt;&#x2F;a&gt;, creator of Advent of Code, along with the whole team, for the work they put into the event every year. Hopefully, I’ll see y’all for the next one!&lt;&#x2F;p&gt;
&lt;p&gt;And since this post comes out January 1st 2022 I also want to wish everyone a better 2022 than 2021 was.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Unlocking the Intel X520-DA2 SFP+</title>
        <published>2021-11-07T00:00:00+00:00</published>
        <updated>2021-11-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/unlocking-the-intel-x520-da2-sfp/"/>
        <id>https://vulpinecitrus.info/blog/unlocking-the-intel-x520-da2-sfp/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/unlocking-the-intel-x520-da2-sfp/">&lt;p&gt;I have recently had the pleasure to acquire a new piece of equipment for one of the servers that I manage in one of our university clubs. Long story short, we were on the verge of a bottleneck happening in our infrastructure at the network interface of the aforementionned server, and decided to invest in a network card and some fiber optics to boost the link speed from 1Gbps ethernet to 10Gbps dual channel.&lt;&#x2F;p&gt;
&lt;p&gt;After some consideration, and because we kept encountering issues with online shopping and delivery, we eventually bought an &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;ark.intel.com&#x2F;content&#x2F;www&#x2F;us&#x2F;en&#x2F;ark&#x2F;products&#x2F;39776&#x2F;intel-ethernet-converged-network-adapter-x520da2.html&quot;&gt;Intel X520-DA2 SFP&#x2F;SFP+ Network Card&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;vulpinecitrus.info&#x2F;blog&#x2F;unlocking-the-intel-x520-da2-sfp&#x2F;intel-x520-da2-e10g42btda.jpg&quot; title=&quot;intel-x520-da2-e10g42btda&quot; alt=&quot;intel-x520-da2-e10g42btda&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;For those who don’t deal with fiber optics, SFP (meaning &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Small_form-factor_pluggable_transceiver&quot;&gt;Small Factor Pluggable&lt;&#x2F;a&gt;) is the standard for the transceivers you can insert into fiber optics cards in order to interface between the card and the fiber optics. SFP and SFP+ are two different standards for these transceivers, and the latter allows for speeds up to 10Gbps. The Intel X520-DA2 can (thankfully) adapt to both modes, although we would rather want to use it with our SFP+ transceivers.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#&quot; aria-label=&quot;Anchor link for: &quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
The Tragedy&lt;&#x2F;h3&gt;
&lt;p&gt;We had high hopes for this card but as soon as we plugged the SFP+ transceivers into the card and our switch and saw no blinking lights, a sinking feeling overtook us. Tragic histrionics aside, we felt a bit panicked. I went to the console of the server and tried to forcefully raise the network interfaces (which were recognized) and saw this&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;~# ip link set enp25s0f1 up&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[....] ixgbe &amp;lt;PCI id&amp;gt;: failed to load because an unsupported SFP+ or QSFP module type was detected.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[....] ixgbe &amp;lt;PCI id&amp;gt;: Reload the driver after installing a supported module.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That was a problem, since we do not own compatible transceivers. Accoding to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.kernel.org&#x2F;doc&#x2F;html&#x2F;v4.20&#x2F;networking&#x2F;ixgbe.html#based-adapters&quot;&gt;official documentation&lt;&#x2F;a&gt;, only a handful of transceivers are compatible, all of them made by Intel (&lt;em&gt;isn’t that funny&lt;&#x2F;em&gt;). We did not even have a compatible transceiver in the “tested 3rd party category”. We could still use those unsupported transceivers for SFP, 1Gbps connection, but paying a month of rent on a piece of equipment that does not deliver or improve your infrastructure is &lt;em&gt;mildly&lt;&#x2F;em&gt; infuriating.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;-1&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#-1&quot; aria-label=&quot;Anchor link for: -1&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
The Investigation&lt;&#x2F;h3&gt;
&lt;p&gt;Initially, we had scant information, and thought our problem laid in fundamental hardware incompatibility. My first queries only led to a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lafibre.info&#x2F;infrastructure&#x2F;pb-compatibilite-sfp&#x2F;&quot;&gt;random french forum thread from 2012&lt;&#x2F;a&gt; telling the story of a person who had the same surprise we did.&lt;&#x2F;p&gt;
&lt;p&gt;As we advanced in our research however, we encountered two important pieces of information :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.kernel.org&#x2F;doc&#x2F;html&#x2F;v4.20&#x2F;networking&#x2F;ixgbe.html&quot;&gt;official documentation&lt;&#x2F;a&gt; does mention a rather odd module parameter called &lt;code&gt;allow_unsupported_sfp&lt;&#x2F;code&gt;, a boolean that bypasses a software check for the transceiver model. We can also find it &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;drivers&#x2F;net&#x2F;ethernet&#x2F;intel&#x2F;ixgbe&#x2F;ixgbe_main.c?id=6b75d88fa81b122cce37ebf17428a849ccd3d0f1#n154&quot;&gt;in the &lt;code&gt;ixgbe&lt;&#x2F;code&gt; linux driver source code&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;static unsigned int&lt;&#x2F;span&gt;&lt;span&gt; allow_unsupported_sfp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;module_param&lt;&#x2F;span&gt;&lt;span&gt;(allow_unsupported_sfp,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; uint&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;MODULE_PARM_DESC&lt;&#x2F;span&gt;&lt;span&gt;(allow_unsupported_sfp,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;		 &amp;quot;Allow unsupported and untested SFP+ modules on 82599-based adapters&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;Some people apparently &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;forums.servethehome.com&#x2F;index.php?threads&#x2F;patching-intel-x520-eeprom-to-unlock-all-sfp-transceivers.24634&#x2F;&quot;&gt;overwrote the firmware of the ES82599 card&lt;&#x2F;a&gt; to “lock” and “unlock” it, letting it either use any SFP+ module, or none.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;That latter posts also mentions some trickery at play in the source code for the linux driver. In order to probe for capabilities, the linux kernel looks for a value stored in the firmware of the network card, at location &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;drivers&#x2F;net&#x2F;ethernet&#x2F;intel&#x2F;ixgbe&#x2F;ixgbe_type.h?id=6b75d88fa81b122cce37ebf17428a849ccd3d0f1#n2069&quot;&gt;&lt;code&gt;IXGBE_DEVICE_CAPS&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, or &lt;code&gt;0x2C&lt;&#x2F;code&gt;. That value is an array of bits that correspond to different capabilities for the network card. Crucially, the bit corresponding to capability &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;drivers&#x2F;net&#x2F;ethernet&#x2F;intel&#x2F;ixgbe&#x2F;ixgbe_type.h?id=6b75d88fa81b122cce37ebf17428a849ccd3d0f1#n2069&quot;&gt;&lt;code&gt;IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; is set to &lt;code&gt;0&lt;&#x2F;code&gt;. Our brave adventurers dumped the firmware of the card with &lt;code&gt;ethtool&lt;&#x2F;code&gt;, located the offset for that device capability bit, flipped it, and flashed the firmware again back onto the EEPROM. This way, multiple people successfully tricked the kernel into allowing any module on the SFP+, confirming that it was never really a hardware issue.&lt;&#x2F;p&gt;
&lt;p&gt;I am not positive that it is entirely malfeasant on the part of Intel, as they would probably want to protect themselves from liability if people used untested (i.e. not their own) SFP+ transceivers in the X520-DA2. With that being said, as we like to say in my language whenever you see a huge, greedy fuck : “Téma la taille du rat”.&lt;&#x2F;p&gt;
&lt;p&gt;At first we thought flashing the firmware was going to be necessary pain, but that we would be done once we had gone through the somewhat stressful process. Thankfully, it would’t even have to come to that.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;-2&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#-2&quot; aria-label=&quot;Anchor link for: -2&quot;&gt;###&lt;&#x2F;a&gt;&amp;nbsp;
The Conclusion (TL;DR)&lt;&#x2F;h3&gt;
&lt;p&gt;As it turns out, posters in the first thread also found the somewhat obscure parameter &lt;code&gt;allow_unsupported_sfp&lt;&#x2F;code&gt; used to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.kernel.org&#x2F;pub&#x2F;scm&#x2F;linux&#x2F;kernel&#x2F;git&#x2F;torvalds&#x2F;linux.git&#x2F;tree&#x2F;drivers&#x2F;net&#x2F;ethernet&#x2F;intel&#x2F;ixgbe&#x2F;ixgbe_phy.c?id=6b75d88fa81b122cce37ebf17428a849ccd3d0f1#n1642&quot;&gt;override the check&lt;&#x2F;a&gt; performed on the ES82599 card, which “”“does not support”“” unofficial SFP+ transceivers. Simply unloading and reloading the &lt;code&gt;ixgbe&lt;&#x2F;code&gt; driver with the correct parameters lets us use any transceivers.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;rmmod&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ixgbe&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;modprobe&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; ixgbe allow_unsupported_sfp=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Making this change persistent can be done with a simple line in your distribution’s kernel module configuration (typically &lt;code&gt;&#x2F;etc&#x2F;modules&lt;&#x2F;code&gt;). One day I might flash the card so we don’t need this parameter, and so the people who use that server after me never have to care about Intel’s shenanigans.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Starting prometheus node exporter after your interface is up </title>
        <published>2021-06-29T00:00:00+00:00</published>
        <updated>2021-06-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/starting-prometheus-node-exporter-after-your-interface-is-up/"/>
        <id>https://vulpinecitrus.info/blog/starting-prometheus-node-exporter-after-your-interface-is-up/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/starting-prometheus-node-exporter-after-your-interface-is-up/">&lt;p&gt;The monitoring stack in my home network depends on a lot of pieces of software all configured to be up and ready every time I have to reboot the gateway (a 8GiB Raspberry Pi 4). One piece of software who, for a while, did not play nice was &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;prometheus.io&#x2F;&quot;&gt;Prometheus&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;(For those just looking for my answer, it’s in the last paragraph).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_setup&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#The_setup&quot; aria-label=&quot;Anchor link for: The_setup&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
The setup&lt;&#x2F;h2&gt;
&lt;p&gt;Essentially, my &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;stats.vulpinecitrus.info&quot;&gt;statistics front-end&lt;&#x2F;a&gt; is running on the VPS that serves my website. It, and my gateway, are both members of a VPN (as in an actual virtual private network). When my gateway comes online, it connects automatically to my VPS (the VPN’s gateway), and Grafana can pull data from it from within the VPN (removing the need to expose my raspberry pi to the wild internet). Similarly, the prometheus database in that stack can pull data from the exporters installed on various machines within my VPN, including the gateway.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_issue&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#The_issue&quot; aria-label=&quot;Anchor link for: The_issue&quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
The issue&lt;&#x2F;h2&gt;
&lt;p&gt;I decided early on that having prometheus’ node exporter expose metrics on every interface was not necessarily advantageous. It could lead to a leak of information from anyone who got access to the network above mine, or just my own (through the wifi, for example).&lt;&#x2F;p&gt;
&lt;p&gt;The option that sets the listen interface can be added in &lt;code&gt;&#x2F;etc&#x2F;default&#x2F;prometheus-node-exporter&lt;&#x2F;code&gt; :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ARGS=&amp;quot;--web.listen-address=AA.ZZ.YY.XX:9100&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;where &lt;code&gt;AA.ZZ.YY.XX&lt;&#x2F;code&gt; is the address of the gateway within my VPN.&lt;&#x2F;p&gt;
&lt;p&gt;However, upon next rebooting the raspberry pi, I was presented with this :&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;vulpinecitrus.info&#x2F;blog&#x2F;starting-prometheus-node-exporter-after-your-interface-is-up&#x2F;prom-grafa-missing-metrics.png&quot; alt=&quot;Suddenly, no metrics on my grafana&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;No logs! Tragedy! Prometheus’ node exporter did not come online. This happened :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;level=error ts=[...] caller=node_exporter.go:198 err=&amp;quot;listen tcp AA.ZZ.YY.XX:9100: bind: cannot assign requested address&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Clearly the problems appear to be that the systemd unit starting &lt;code&gt;prometheus-node-exporter&lt;&#x2F;code&gt; is not written to expect my wireguard interface before starting itself.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#&quot; aria-label=&quot;Anchor link for: &quot;&gt;##&lt;&#x2F;a&gt;&amp;nbsp;
The solution&lt;&#x2F;h2&gt;
&lt;p&gt;My wireguard interface is configured and raised automatically at boot thanks to a service called &lt;code&gt;wg-quick&lt;&#x2F;code&gt;, with the specific target &lt;code&gt;wg-quick@iiiii.service&lt;&#x2F;code&gt; where &lt;code&gt;iiiii&lt;&#x2F;code&gt; is the name of my VPN interface.&lt;&#x2F;p&gt;
&lt;p&gt;Running &lt;code&gt;systemctl status prometheus-node-exporter&lt;&#x2F;code&gt; shows you that prometheus node exporter failed to start, but it also gives you the location of the unit file associated with that service. Open it (as root obviously) and, in the &lt;code&gt;Unit&lt;&#x2F;code&gt; section at the beginning of the file, you may add&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;After=wg-quick@iiiii.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then you can reload systemd’s units (&lt;code&gt;systemctl daemon-reload&lt;&#x2F;code&gt;) and reboot&#x2F;restart the unit. (Note: a reboot is not required but my issue is with the behaviour on a fresh reboot).&lt;&#x2F;p&gt;
&lt;p&gt;In case your situation is not exactly like mine (you are using different software, or you want to expect an interface not linked to a specific unit), you may want to look at what &lt;code&gt;systemctl list-units --no-pager | grep net-devices&lt;&#x2F;code&gt; shows you. Virtual device services created by systemd might also work in that setup (although I have yet to try that setup).&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The Services of Vulpine Citrus</title>
        <published>2021-02-08T00:00:00+00:00</published>
        <updated>2021-02-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/the-services-of-vulpine-citrus/"/>
        <id>https://vulpinecitrus.info/blog/the-services-of-vulpine-citrus/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/the-services-of-vulpine-citrus/">&lt;p&gt;I’m coming close to a year of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;vulpinecitrus.info&#x2F;&quot;&gt;VulpineCitrus&lt;&#x2F;a&gt; being up and running, and over the course of a year it has been a tremendously useful tool for me to deploy so many services that have changed my (and to an extent others’) daily routines. It has also been a great way to learn a lot of technological solutions I had heard of before but never managed to deploy at home.&lt;&#x2F;p&gt;
&lt;p&gt;Back in the days when I shared a VPS I had &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;tt-rss.org&#x2F;&quot;&gt;TinyTinyRSS&lt;&#x2F;a&gt;, a small web-based RSS stream aggregation tool, running and configured.
I personally use it to keep up with local newspaper that have not yet dropped their RSS feeds (and it works well). When I migrated, the first
things I had to do were &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;vulpinecitrus.info&#x2F;blog&#x2F;new-server-new-system-new-postgresql-database&#x2F;&quot;&gt;moving my PostgreSQL clusters&lt;&#x2F;a&gt; and installing TTRSS again. It has been working like a charm for a year.&lt;&#x2F;p&gt;
&lt;p&gt;Later, when the pandemic happened and I was back home, stuck with a lot of time, I started dabbling with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.wireguard.com&#x2F;&quot;&gt;WireGuard&lt;&#x2F;a&gt;, the small yet powerful VPN system now shipped with the Linux kernel (for versions &lt;code&gt;&amp;gt;=5.6&lt;&#x2F;code&gt;). I had a lot of fun connecting the small network in my bedroom (which I should discuss for the sheer technical interest of it) and had a couple painful encounters with the kernel’s routing system (both in IPv4 and IPv6) and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Netfilter&quot;&gt;NetFilter&lt;&#x2F;a&gt; framework (usually through &lt;code&gt;ip(6)tables&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;Another service I brought over from my old VPS, but haven’t been using for a while, is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;drawpile.net&#x2F;&quot;&gt;Drawpile&lt;&#x2F;a&gt;. It’s good fun to doodle with friends from time to time, and last summer I decided to update the clunky and old server I had kept running on here. I was &lt;em&gt;both surprised and afraid&lt;&#x2F;em&gt; to find out that they had switched to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.docker.com&#x2F;&quot;&gt;Docker&lt;&#x2F;a&gt; as a deployment solution. They also work in a distributed architecture as well, so I had some good fun yelling at docker. It is a technology I already know from my systems and network experience, but it was the first time I had to deploy a solution on my own using pre-made dockers. It went well (although I do remember being utterly confused trying to use the old client-side tools and not understanding right-away why it wasn’t working). I should update it again, in fact. Thankfully, it’s rather lightweight, and it works. The rather funny side effect of having &lt;code&gt;draw.vulpinecitrus.info&lt;&#x2F;code&gt; point to the same VPS as everything else is that trying to access that domain with a browser will give you a &lt;code&gt;SSL_ERROR_BAD_CERT_DOMAIN&lt;&#x2F;code&gt; error (my web certificate is only valid for &lt;code&gt;vulpinecitrus.info&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;Let’s talk about &lt;code&gt;apache2&lt;&#x2F;code&gt; by the way. I did not know it back in July&#x2F;August but when I deployed a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gitea.io&quot;&gt;Gitea&lt;&#x2F;a&gt;, I learned a lot of &lt;em&gt;extremely&lt;&#x2F;em&gt; useful things about reverse proxies, and specifically Apache’s reverse-proxy. Using recommendations from Gitea’s README and some help from Apache’s manual I cobbled together the right &lt;code&gt;site-enabled&lt;&#x2F;code&gt; configuration file for Apache’s reverse-proxy to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;&quot;&gt;server me gitea&lt;&#x2F;a&gt;, which &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;Lymkwi&#x2F;&quot;&gt;I have been using&lt;&#x2F;a&gt; for some time now to host code for people and some archives of projects, most recently including &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git.vulpinecitrus.info&#x2F;Lymkwi&#x2F;AOC2020&quot;&gt;Advent of Code 2020&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The final service I moved from my VPS in March is the couple of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;discordpy.readthedocs.io&#x2F;en&#x2F;latest&#x2F;&quot;&gt;Discord Bots&lt;&#x2F;a&gt; I run for me and my friends, an especially sensitive operation since one of these bots ended up being an important part of one Discord server I help ran for my college promotion. A couple &lt;code&gt;crontab&lt;&#x2F;code&gt; lines and &lt;code&gt;pyenv&lt;&#x2F;code&gt; hacks were all I needed.&lt;&#x2F;p&gt;
&lt;p&gt;In September I moved in with a group of friends and found myself needing some sort of cloud storage. In order to synchronize my class documents across multiple devices, I had been using &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;git-scm.org&quot;&gt;git&lt;&#x2F;a&gt;, which worked for a while, but gave up with large media files (lessons our teachers recorded for example). Within my network, I had started using a Samba server, running on my Raspberry Pi 2B Rev 1.1, but said RPi couldn’t handle a hard drive, so massive storage was impossible. In early October, when school moved off-line again, I heard about &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;nextcloud.com&#x2F;&quot;&gt;Nextcloud&lt;&#x2F;a&gt; again, a full cloud solution (although I hate the word “cloud”). It was a hassle to deploy, since the easiest way to accommodate for storage was to have the service run at home, and proxy to it from my VPS. I combined the aforementioned wireguard VPN along with Apache’s reverse proxy, and after roughly two days of googling and checking uploads, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;cloud.vulpinecitrus.info&#x2F;&quot;&gt;VC’s Cloud&lt;&#x2F;a&gt; was up and running.&lt;&#x2F;p&gt;
&lt;p&gt;Lately, not much has moved. A lot of my needs are currently satisfied. I discovered &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;bitwarden.com&#x2F;&quot;&gt;Bitwarden&lt;&#x2F;a&gt;, which was horribly painful to deploy and configure (it deployed no less than 10 dockers), so I switched to the compatible &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dani-garcia&#x2F;vaultwarden&quot;&gt;Rust implementation&lt;&#x2F;a&gt; by Daniel Garcia, which was ready to use after only half an hour of cloning docker images.&lt;&#x2F;p&gt;
&lt;p&gt;I can also mention a couple of dev experiences VC has afforded me. I made my own log file separator in bash, a rather painful experience. Running the Discord bots gave me an excuse to learn Discord Py to make some useful modules for me and my classmates.&lt;&#x2F;p&gt;
&lt;p&gt;I will also mention in passing that I deployed the mail server for Vulpinecitrus on my own, using &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.dovecot.org&#x2F;&quot;&gt;Dovecot&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.postfix.org&#x2F;&quot;&gt;Postfix&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;spamassassin.apache.org&#x2F;&quot;&gt;SpamAssassin&lt;&#x2F;a&gt; (the classic triad), and I have plans to dive into how I did it in a later post. I also had an IRC server but since I don’t actually have a use for it, the SystemD unit is disabled by default.&lt;&#x2F;p&gt;
&lt;p&gt;So that’s a year of VulpineCitrus. Hopefully I get to do crazy new things! I am thinking of tinkering with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;glitch-soc.github.io&#x2F;docs&#x2F;&quot;&gt;GlitchSoc&lt;&#x2F;a&gt;, a Mastodon fork, as well as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;grafana.com&#x2F;&quot;&gt;Grafana&lt;&#x2F;a&gt; (which I already know a lot about but haven’t put on VC yet, it’s in my home network).&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>New server. New system. New PostgreSQL database</title>
        <published>2020-03-06T00:00:00+00:00</published>
        <updated>2020-03-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/new-server-new-system-new-postgresql-database/"/>
        <id>https://vulpinecitrus.info/blog/new-server-new-system-new-postgresql-database/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/new-server-new-system-new-postgresql-database/">&lt;p&gt;A few days ago, I launched a website called “Vulpine Citrus”, meant to act as my front end with the rest of the world. Before that, I used to run a lot of my personal services on a server shared with a friend. After I bought my domain name, and VPS, I decided to begin moving my services onto my new server and stop hogging the storage space on that other, shared system.&lt;&#x2F;p&gt;
&lt;p&gt;I had, until then, gracefully escaped anything vaguely technically about managing database systems. I still am far from understanding the deep, underlying concepts of DB managers. However, I had an entire computer science semester of “Databases 101” last year, and I felt a little more enclined to start and play around with the PostgreSQL database system.&lt;&#x2F;p&gt;
&lt;p&gt;I will show you how to dump and export databases from one cluster to another on different machines. Both systems will be running Debian 9 or Debian 10. As far as my understanding goes, and that is all you need to understand this article, a cluster is a single instance of postgreSQL running on a system, with multiple clusters able to run at the same time, using different versions of the software.&lt;&#x2F;p&gt;
&lt;p&gt;On the former host of my database, I was running PostgreSQL 9.6. My cluster was called “9.6 main”. On the new system, I am running PostgreSQL 11. My cluster is called “11 main”. I will only be exporting one database, and creating new users. If you wish to dump and export a whole cluster, you will have to find someone more competent.&lt;&#x2F;p&gt;
&lt;p&gt;First off, logged into my new system, I had to install, enable and start postgresql 11&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;apt&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; install postgresql&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;systemctl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; enable postgresql&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;systemctl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; start postgresql&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can check whether or not the server is running by using&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;pg_lsclusters&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Which should show something similar to&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Ver Cluster Port Status Owner    Data directory              Log file&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;11  main    5432 online postgres &#x2F;var&#x2F;lib&#x2F;postgresql&#x2F;11&#x2F;main &#x2F;var&#x2F;log&#x2F;postgresql&#x2F;postgresql-11-main.log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, head off to the old system. Log in as the owner of the database you wish to export (or any account capable of reading the database, really).&lt;&#x2F;p&gt;
&lt;p&gt;You can export the old database by using &lt;code&gt;pg_dump&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;pg_dump&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -U&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; owner_of_database name_of_database&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; my_database.pgsql&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What you’re doing, essentially, is generating a PostgreSQL script capable of creating a carbon copy of your database as seen by user &lt;code&gt;owner_of_database&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;You can copy that script by any mean to the new system. I personally use &lt;code&gt;scp&lt;&#x2F;code&gt; over &lt;code&gt;ssh&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Back to the new system, you will have to create your (empty) database and the role associated to the user(s) that will access it. The tools called &lt;code&gt;createuser&lt;&#x2F;code&gt; and &lt;code&gt;createdb&lt;&#x2F;code&gt; do the job fantastically, such that you don’t need to write a single line of SQL.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;createuser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; --interactive --pwprompt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can tell PostgreSQL that your new user can create databases, or not, roles, or not, it depends on what kind of user you want. Mine is a simple account meant to just read and write the database without doing anything complex or risky with its structure, or any other database.&lt;&#x2F;p&gt;
&lt;p&gt;The proper database can be created using&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;createdb&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; my_owner_name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -O&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; my_owner_name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;createdb&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; my_database_name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -O&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; my_owner_name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The new user will most probably require a database bear their name. When you log into the server without providing a database, this is where you end up. It does not fulfill any other purpose, but I like to create it as well.&lt;&#x2F;p&gt;
&lt;p&gt;Once everything is in place, and you can successfully log in using &lt;code&gt;psql -U my_owner_name&lt;&#x2F;code&gt; (or if you can’t because there are no databases), create the carbon copy of your former database by executing the dumped script&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;psql -U my_owner_name my_database_name &amp;lt; dump.pgsql&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If everything goes smoothly, you should only see a lot of PostgreSQL instructions fly by in the command line. When the database is created, you can try and log into it. Check whether you can successfully log in&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;psql -U my_owner_name my_database_name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once you are sure that everything was transferred as you wanted, you can go back to your previous system, and, optionally, clean up the database(s) you exported.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;dropdb&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; my_database_name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And you’ll be good to go! 🦊&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The Vulpine Citrus </title>
        <published>2020-03-05T00:00:00+00:00</published>
        <updated>2020-03-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/the-vulpine-citrus/"/>
        <id>https://vulpinecitrus.info/blog/the-vulpine-citrus/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/the-vulpine-citrus/">&lt;p&gt;This is the official launch of Vulpine Citrus, my own personal web site! Whenever I find something interesting to talk about, or want to show a cool thing I’ve learned, it will end up here.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Baby&#x27;s first BrainF*ck clone : The Moostar Programming Language </title>
        <published>2019-07-08T00:00:00+00:00</published>
        <updated>2019-07-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              lymkwi (Lux Amelia)
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vulpinecitrus.info/blog/babys-first-brainf-ck-clone-the-moostar-programming-language/"/>
        <id>https://vulpinecitrus.info/blog/babys-first-brainf-ck-clone-the-moostar-programming-language/</id>
        
        <content type="html" xml:base="https://vulpinecitrus.info/blog/babys-first-brainf-ck-clone-the-moostar-programming-language/">&lt;p&gt;A few years ago, my journey into coding led me to the dark alleys of GNU Assembly. I quickly realized that the difficulties of Assembly made it almost impossible for me to use it in my daily coding life.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;When it takes you three hours to reimplement &lt;code&gt;strlen&lt;&#x2F;code&gt; correctly, and you’re used to processing natural strings of characters, you may begin to feel like this is not the language for you.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;– Me, two years ago&lt;&#x2F;p&gt;
&lt;p&gt;On my way up from that dark pit of black magic I encountered a curious little fella I had heard of many years prior : &lt;strong&gt;BrainFuck&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;BrainFuck is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.iwriteiam.nl&#x2F;Ha_bf_Turing.html&quot;&gt;Turing-Complete&lt;&#x2F;a&gt; and while it could theoretically let us implement any and all computable problem… BrainFuck may not be the best fit for most complex purposes.&lt;&#x2F;p&gt;
&lt;p&gt;I mean, just look at this hello world.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;++++++++++[&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	&amp;gt;+++++++&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	&amp;gt;++++++++++&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	&amp;gt;+++&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	&amp;gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	&amp;lt;&amp;lt;&amp;lt;&amp;lt;-&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt;++.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt;+.+++++++..&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+++.&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;++.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&amp;lt;+++++++++++++++.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+++.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;------.--------.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt;+.&amp;gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Of course, I was not content with simply making an interpreter. I started Moostar with the intent of making an interpreter, but quickly decided to add one features to standard brainfuck that I found gave it more power : the ability to creature functions, along with the inclusion of many fundamental arithmetic operations right into the interpreter.&lt;&#x2F;p&gt;
&lt;p&gt;For example, here’s how you can write two multiplications in Moostar.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt;++&amp;gt;+++++&amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;~mul;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The hexadecimal dump of the output should reveal a single byte at value 0x08.&lt;&#x2F;p&gt;
&lt;p&gt;Currently, Moostar implements all of the following standard subroutines.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	&#x2F;* &amp;#39;this&amp;#39; is the object representing the interpreter *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	this-&amp;gt;function_register[&amp;quot;sub_5&amp;quot;] = &amp;quot;-----&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	this-&amp;gt;function_register[&amp;quot;sub_10&amp;quot;] = &amp;quot;----------&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	this-&amp;gt;function_register[&amp;quot;add_5&amp;quot;] = &amp;quot;+++++&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	this-&amp;gt;function_register[&amp;quot;add_10&amp;quot;] = &amp;quot;++++++++++&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	this-&amp;gt;function_register[&amp;quot;imove&amp;quot;] = &amp;quot;[-&amp;gt;+&amp;lt;]&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	this-&amp;gt;function_register[&amp;quot;dmove&amp;quot;] = &amp;quot;[-&amp;lt;+&amp;gt;]&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	this-&amp;gt;function_register[&amp;quot;clean&amp;quot;] = &amp;quot;[-]&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	std::string scan8;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	for (size_t i = 0; i &amp;lt; 8; i++)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		scan8.append(&amp;quot;.&amp;gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	for (size_t i = 0; i &amp;lt; 8; i++)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		scan8.append(&amp;quot;&amp;lt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	this-&amp;gt;function_register[&amp;quot;scan8&amp;quot;] = scan8;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	this-&amp;gt;function_register[&amp;quot;scan16&amp;quot;] = scan8.substr(0,16) + scan8.substr(0,16) + scan8.substr(16,8) + scan8.substr(16,8);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	this-&amp;gt;function_register[&amp;quot;foreach_cpy&amp;quot;] = &amp;quot;&amp;gt;[&amp;gt;[-&amp;gt;+&amp;lt;&amp;lt;&amp;lt;+&amp;gt;&amp;gt;]&amp;gt;[-&amp;lt;+&amp;gt;]&amp;lt;&amp;lt;-]&amp;gt;[-]&amp;lt;&amp;lt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	this-&amp;gt;function_register[&amp;quot;add&amp;quot;] = &amp;quot;&amp;gt;[-&amp;lt;+&amp;gt;]&amp;lt;&amp;quot;; &#x2F;&#x2F; :R:X:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	this-&amp;gt;function_register[&amp;quot;sub&amp;quot;] = &amp;quot;&amp;gt;[-&amp;lt;-&amp;gt;]&amp;lt;&amp;quot;; &#x2F;&#x2F; :R:Y:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	this-&amp;gt;function_register[&amp;quot;mul&amp;quot;] = this-&amp;gt;function_register[&amp;quot;foreach_cpy&amp;quot;];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	this-&amp;gt;function_register[&amp;quot;pow&amp;quot;] = &amp;quot;&amp;gt;&amp;gt;&amp;gt;+&amp;lt;&amp;lt;[&amp;gt;&amp;gt;[-&amp;gt;+&amp;lt;]&amp;lt;[-&amp;gt;&amp;gt;&amp;gt;+&amp;gt;+&amp;lt;&amp;lt;&amp;lt;&amp;lt;]&amp;gt;&amp;gt;&amp;gt;&amp;gt;[-&amp;lt;&amp;lt;&amp;lt;&amp;lt;+&amp;gt;&amp;gt;&amp;gt;&amp;gt;]&amp;lt;&amp;lt;&amp;lt;~foreach_cpy;&amp;lt;&amp;lt;-]&amp;gt;&amp;gt;[-&amp;lt;&amp;lt;&amp;lt;+&amp;gt;&amp;gt;&amp;gt;]&amp;lt;[-]&amp;lt;&amp;lt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	this-&amp;gt;function_register[&amp;quot;eq&amp;quot;] = &amp;quot;[-&amp;gt;-&amp;lt;]+&amp;gt;[&amp;lt;[-]&amp;gt;[-]][-]&amp;lt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	this-&amp;gt;function_register[&amp;quot;neq&amp;quot;] = &amp;quot;[-&amp;gt;-&amp;lt;]&amp;gt;[[-]&amp;lt;+&amp;gt;][-]&amp;lt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	this-&amp;gt;function_register[&amp;quot;lt&amp;quot;] = &amp;quot;&amp;gt;[-&amp;gt;+&amp;lt;]&amp;lt;[-&amp;gt;+&amp;lt;]&amp;gt;+&amp;gt;+&amp;gt;&amp;gt;+&amp;lt;&amp;lt;&amp;lt;[-&amp;gt;-[&amp;gt;]&amp;lt;&amp;lt;]&amp;gt;&amp;gt;&amp;gt;[&amp;lt;&amp;lt;[-]&amp;lt;&amp;lt;+&amp;gt;&amp;gt;&amp;gt;]&amp;gt;-&amp;lt;&amp;lt;[-]&amp;lt;[-]&amp;lt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	this-&amp;gt;function_register[&amp;quot;gt&amp;quot;] = &amp;quot;&amp;gt;[-&amp;gt;+&amp;lt;]&amp;gt;&amp;gt;&amp;gt;+&amp;lt;&amp;lt;&amp;lt;&amp;lt;[-&amp;gt;+&amp;lt;]&amp;gt;&amp;gt;[-&amp;lt;-[&amp;lt;]&amp;gt;&amp;gt;]&amp;gt;[-&amp;lt;&amp;lt;[-]&amp;lt;]&amp;gt;[-&amp;lt;&amp;lt;&amp;lt;[-]&amp;lt;+&amp;gt;&amp;gt;]&amp;lt;&amp;lt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	this-&amp;gt;function_register[&amp;quot;m@0&amp;quot;] = &amp;quot;^[-]\\&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	&#x2F;* Stuff *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;(let’s all walk past that hilarious mistake of “interpreter”&#x2F;“interpretor”, younger me’s English was more than dubious)&lt;&#x2F;p&gt;
&lt;p&gt;In general, one would declare a procedure thusly.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(proc_name):{instructions}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It is useful to add a comment alongside a function’s definition to denote the position of its parameters, results, and all the cells it will need for its processing. For example, see that comment at the end of a definition for &lt;code&gt;~power&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:R:X:Y:0_:1_:2_:3_:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This comment indicates that once &lt;code&gt;pow&lt;&#x2F;code&gt; is called, it will compute X to the power of Y, require the four neighbouring cells to do so, and place the result in the cell we call it from.&lt;&#x2F;p&gt;
&lt;p&gt;Currently, Moostar doesn’t check for dependencies of functions, and one could write a program that would send the interpreter into an infinite loop of procedures calling each other.&lt;&#x2F;p&gt;
&lt;p&gt;Yet, there is more to Moostar than simply adding standard functions. As you might have noticed from the weird circumflex character in my last command, &lt;code&gt;m@0&lt;&#x2F;code&gt;, I extended the charset beyond the simple ability to declare procedures. Two characters were introduced beyond those used in standard BrainFuck, and those for procedural syntax.
The first such character, the circumflex accent, switches the interpreter into ‘Meta Tape’ mode, while the backslash switches the interpreter back into ‘Data Tape’ mode.&lt;&#x2F;p&gt;
&lt;p&gt;The ‘Meta Tape’, or ‘Meta Registers Tape’ is a set of cells containing and controlling data related to the machine’s function itself. Originally, they were designed to directly modify CPU registers during execution. Two seconds after I had that idea, when I realized it could easily be exploited to bug the heck out of Moostar, I slowed down and only implemented a control register for the data pointer’s position. Interestingly, a legacy name for that meta tape remains in the code : &lt;code&gt;this-&amp;gt;ioregs&lt;&#x2F;code&gt; (for I&#x2F;O registers).&lt;&#x2F;p&gt;
&lt;p&gt;Now, the pointer on the meta tape and the pointer on the data tape are not the same. Thus, by switching to the meta tape’s zero register, we can chose what cell we will land on when we switch back to data.
This is actually what the &lt;code&gt;m@0&lt;&#x2F;code&gt; procedure does, by resetting the value in meta register 0 (&lt;code&gt;data_pointer_pos&lt;&#x2F;code&gt;) to 0, and switching back to the data tape.&lt;&#x2F;p&gt;
&lt;p&gt;You can find the source code for moostar on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;LeMagnesium&#x2F;moostar&quot;&gt;GitHub&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
