<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Blog on blog.gnoack.org</title>
    <link>https://blog.gnoack.org/</link>
    <description>Recent content on blog.gnoack.org</description>
    <pubDate>Sun, 12 Apr 2026 08:54:52 +0000</pubDate>
    <item>
      <title>Nutella is in space</title>
      <link>https://blog.gnoack.org/post/nutella-in-space</link>
      <description>&lt;p&gt;The big question for science is: Does it stay on the ground in the jar, or does it form floating lumps?&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/nutella-in-space/</guid>
      <pubDate>Thu, 09 Apr 2026 20:35:42 +0000</pubDate>
    </item>
    <item>
      <title>Parameterized testing: You want Inputs and Outputs</title>
      <link>https://blog.gnoack.org/post/parameterized-testing</link>
      <description>&lt;p&gt;Is your test in the business of calculating the expected output from the inputs?&lt;/p&gt;&#xA;&lt;p&gt;Then your test is duplicating the logic from the code under test.&lt;/p&gt;&#xA;&lt;p&gt;There is a reason why &lt;a href=&#34;https://testing.googleblog.com/2014/07/testing-on-toilet-dont-put-logic-in.html&#34;&gt;too much logic in tests is frowned upon&lt;/a&gt;:&#xA;If you implement the same logic twice,&#xA;you are &lt;em&gt;prone to repeat the same mistakes in the test which you already made in the real implementation&lt;/em&gt;.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bad&#34;&gt;for c in [&#xA;  Case(socket_type=SOCK_STREAM, fruit=&amp;quot;Apple&amp;quot;),&#xA;  Case(socket_type=SOCK_STREAM, fruit=&amp;quot;Orange&amp;quot;),&#xA;  Case(socket_type=SOCK_DGRAM,  fruit=&amp;quot;Apple&amp;quot;),&#xA;  Case(socket_type=SOCK_DGRAM,  fruit=&amp;quot;Orange&amp;quot;),&#xA;]:&#xA;  # Oh no, surprise logic in the test!&#xA;  # This becomes hard to find when the test gets longer.&#xA;  expected = 1&#xA;  if c.socket_type == SOCK_STREAM and c.fruit == &amp;quot;Orange&amp;quot;:&#xA;    expected = 0  # Expecting nothing in this case&#xA;&#xA;  self.assertEqual(expected, operation(c.socket_type, c.fruit))&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Better is to flatten out the expected results into the test table and remove that logic from the test:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-good&#34;&gt;for c in [&#xA;  Case(socket_type=SOCK_STREAM, fruit=&amp;quot;Apple&amp;quot;,  expected=1),&#xA;  Case(socket_type=SOCK_STREAM, fruit=&amp;quot;Orange&amp;quot;, expected=0),  # special case&#xA;  Case(socket_type=SOCK_DGRAM,  fruit=&amp;quot;Apple&amp;quot;,  expected=1),&#xA;  Case(socket_type=SOCK_DGRAM,  fruit=&amp;quot;Orange&amp;quot;, expected=1),&#xA;]:&#xA;  self.assertEqual(c.expected, operation(c.socket_type, c.fruit))&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/landlock-lsm/go-landlock/blob/main/landlock/restrict_downgrade_test.go&#34;&gt;A non-trivial real-world example&lt;/a&gt; (from the Go-Landlock library).&lt;/p&gt;&#xA;&lt;div id=&#39;pikchr-0&#39; class=&#39;pikchr&#39;&gt;&#xA;&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:472px&#39;&gt;&#xA;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 472.32 163.253&#34;&gt;&#xA;&lt;path d=&#34;M2.16,161.093L110.16,161.093L110.16,89.0929L2.16,89.0929Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,128,0);&#34; /&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;115.013&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,128,0)&#34; dominant-baseline=&#34;central&#34;&gt;provided&lt;/text&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;135.173&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,128,0)&#34; dominant-baseline=&#34;central&#34;&gt;inputs&lt;/text&gt;&#xA;&lt;polygon points=&#34;182.16,125.093 170.64,129.413 170.64,120.773&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M110.16,125.093L176.4,125.093&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M182.16,161.093L290.16,161.093L290.16,89.0929L182.16,89.0929Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;236.16&#34; y=&#34;104.933&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;system&lt;/text&gt;&#xA;&lt;text x=&#34;236.16&#34; y=&#34;125.093&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;under&lt;/text&gt;&#xA;&lt;text x=&#34;236.16&#34; y=&#34;145.253&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;test&lt;/text&gt;&#xA;&lt;polygon points=&#34;362.16,125.093 350.64,129.413 350.64,120.773&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M290.16,125.093L356.4,125.093&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M362.16,161.093L470.16,161.093L470.16,89.0929L362.16,89.0929Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,128,0);&#34; /&gt;&#xA;&lt;text x=&#34;416.16&#34; y=&#34;115.013&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,128,0)&#34; dominant-baseline=&#34;central&#34;&gt;expected&lt;/text&gt;&#xA;&lt;text x=&#34;416.16&#34; y=&#34;135.173&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,128,0)&#34; dominant-baseline=&#34;central&#34;&gt;outputs&lt;/text&gt;&#xA;&lt;text x=&#34;236.16&#34; y=&#34;12.24&#34; text-anchor=&#34;middle&#34; font-style=&#34;italic&#34; fill=&#34;rgb(0,128,0)&#34; dominant-baseline=&#34;central&#34;&gt;you want both&lt;/text&gt;&#xA;&lt;text x=&#34;236.16&#34; y=&#34;32.4&#34; text-anchor=&#34;middle&#34; font-style=&#34;italic&#34; fill=&#34;rgb(0,128,0)&#34; dominant-baseline=&#34;central&#34;&gt;inputs and outputs&lt;/text&gt;&#xA;&lt;text x=&#34;236.16&#34; y=&#34;52.56&#34; text-anchor=&#34;middle&#34; font-style=&#34;italic&#34; fill=&#34;rgb(0,128,0)&#34; dominant-baseline=&#34;central&#34;&gt;in the test table&lt;/text&gt;&#xA;&lt;polygon points=&#34;56.16,89.0929 51.84,77.5729 60.48,77.5729&#34; style=&#34;fill:rgb(0,128,0)&#34;/&gt;&#xA;&lt;path d=&#34;M151.546,32.4 L 103.853,32.4 Q 56.16,32.4 56.16,57.8665 L 56.16,83.3329&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,128,0);stroke-dasharray:2.16,7.2;&#34; /&gt;&#xA;&lt;polygon points=&#34;416.16,89.0929 411.84,77.5729 420.48,77.5729&#34; style=&#34;fill:rgb(0,128,0)&#34;/&gt;&#xA;&lt;path d=&#34;M320.774,32.4 L 368.467,32.4 Q 416.16,32.4 416.16,57.8665 L 416.16,83.3329&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,128,0);stroke-dasharray:2.16,7.2;&#34; /&gt;&#xA;&lt;/svg&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;This is one of these articles that I&amp;rsquo;m writing just so that I can point to it later. &lt;em&gt;In a code review.&lt;/em&gt; :)&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/parameterized-testing/</guid>
      <pubDate>Wed, 11 Feb 2026 23:58:31 +0000</pubDate>
    </item>
    <item>
      <title>She sells Z-Shells at the Z-Shore</title>
      <link>https://blog.gnoack.org/post/landlock-island</link>
      <description>&lt;p&gt;Mickaël&amp;rsquo;s FOSDEM talk about the &lt;a href=&#34;https://github.com/landlock-lsm/island&#34;&gt;Island sandboxing tool&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://fosdem.org/2026/schedule/event/EW8M3R-island/&#34;&gt;https://fosdem.org/2026/schedule/event/EW8M3R-island/&lt;/a&gt; (with 📽️ video!)&lt;/p&gt;&#xA;&lt;p&gt;The Island sandboxing tool comes with tight integration with the &lt;code&gt;zsh&lt;/code&gt;, to make sandboxing a part of the everyday workflow.&lt;/p&gt;&#xA;&lt;p&gt;When you use that integration, the directory that you are in determines the Landlock policy which is then applied to the commands that you run.&lt;/p&gt;&#xA;&lt;p&gt;🐚&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/landlock-island/</guid>
      <pubDate>Wed, 11 Feb 2026 23:49:43 +0000</pubDate>
    </item>
    <item>
      <title>Martin Luther King Day</title>
      <link>https://blog.gnoack.org/post/mlk-day-2026</link>
      <description>&lt;iframe width=&#34;560&#34; height=&#34;315&#34; src=&#34;https://www.youtube.com/embed/RcVZfJO01NI?si=FOWXlvFOLbnNW1Rr&#34; title=&#34;YouTube video player&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; allowfullscreen&gt;&lt;/iframe&gt;&#xA;&lt;p&gt;The time is overdue. Stevie Wonder is amazing. 🎉&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/mlk-day-2026/</guid>
      <pubDate>Mon, 19 Jan 2026 20:39:26 +0000</pubDate>
    </item>
    <item>
      <title>FOSDEM 2026: It is happening!</title>
      <link>https://blog.gnoack.org/post/fosdem2026</link>
      <description>&lt;p&gt;I will be at FOSDEM 2026 this year,&#xA;with a hunger for Belgian waffles&#xA;and a big bag of freshly printed Landlock stickers.&lt;/p&gt;&#xA;&lt;p&gt;I am looking forward to meeting you all again there!&lt;/p&gt;&#xA;&lt;p&gt;If you are dropping by, and want to chat in person, send me a note!&lt;/p&gt;&#xA;&lt;p&gt;I am collecting links over at &lt;a href=&#34;https://wiki.gnoack.org/FosdemTwentySix&#34;&gt;https://wiki.gnoack.org/FosdemTwentySix&lt;/a&gt;. (You might want to double check regarding a potential railway strike on the 30th.)&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/fosdem2026/</guid>
      <pubDate>Sun, 18 Jan 2026 23:20:25 +0000</pubDate>
    </item>
    <item>
      <title>Google Big Sleep: Linux Vulnerabilities</title>
      <link>https://blog.gnoack.org/post/bigsleep-linux</link>
      <description>&lt;p&gt;I am excited to share that my team at Google,&#xA;Google Big Sleep,&#xA;has published the reports&#xA;for a few (now fixed) Linux kernel vulnerabilities:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://issuetracker.google.com/issues/458654612&#34;&gt;BIGSLEEP-458654612&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://issuetracker.google.com/issues/462435176&#34;&gt;BIGSLEEP-462435176&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://issuetracker.google.com/issues/463332873&#34;&gt;BIGSLEEP-463332873&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The full public list of issues discovered by Google Big Sleep&#xA;is at &lt;a href=&#34;https://goo.gle/bigsleep&#34;&gt;https://goo.gle/bigsleep&lt;/a&gt;.&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/bigsleep-linux/</guid>
      <pubDate>Tue, 06 Jan 2026 19:45:46 +0000</pubDate>
    </item>
    <item>
      <title>Lore links in mutt</title>
      <link>https://blog.gnoack.org/post/lore-links-in-mutt</link>
      <description>&lt;p&gt;The following script takes an email on stdin and constructs the associated &lt;a href=&#34;https://lore.kernel.org&#34;&gt;lore.kernel.org&lt;/a&gt; link based on the email&amp;rsquo;s &lt;code&gt;Message-ID&lt;/code&gt; header.  The script copies the link to the Wayland clipboard and posts a notification.&lt;/p&gt;&#xA;&lt;p&gt;The escaping story is not perfect, but at least it is secure.  (It only supports the most common characters in the message ID, but then it also can&amp;rsquo;t accidentally be misused for escaping shenanigans.)&lt;/p&gt;&#xA;&lt;p&gt;The script &lt;code&gt;email-to-lore&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;#!/bin/sh&#xA;awk &#39;&#xA;/^Message-ID: &amp;lt;[a-zA-Z0-9/+-=.@]+&amp;gt;/ {&#xA;  match($2, /&amp;lt;([^&amp;gt;]+)/, a);&#xA;  system(&amp;quot;wl-copy -- https://lore.kernel.org/all/&amp;quot; a[1] &amp;quot;/&amp;quot;);&#xA;  system(&amp;quot;notify-send --expire-time=5000 \&amp;quot;Copied to clipboard\&amp;quot; https://lore.kernel.org/&amp;quot; a[1] &amp;quot;/&amp;quot;);&#xA;}&#xA;&#39;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The script is registered in the &lt;a href=&#34;http://mutt.org&#34;&gt;&lt;code&gt;mutt&lt;/code&gt;&lt;/a&gt; configuration in the following way:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;macro pager l &amp;quot;| /path/to/email-to-lore&amp;lt;enter&amp;gt;&amp;quot; &amp;quot;Copy a Lore link to the clipboard&amp;quot;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;When you now hit &lt;code&gt;l&lt;/code&gt; in the mutt email view (pager), you get a desktop notification indicating that the link has been copied to the clipboard and you can use the usual shortcuts to paste it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;FYI: Existing alternatives:&lt;/strong&gt;&#xA;An alternative to this is the Python &lt;a href=&#34;https://github.com/danrue/lorifier&#34;&gt;&lt;code&gt;lorifier&lt;/code&gt;&lt;/a&gt; script,&#xA;which adds the Lore link to the mail headers before display.  &lt;code&gt;lorifier&lt;/code&gt; is probably smarter about detecting the mailing list which the mail was posted to, whereas my awk script only generates the &amp;ldquo;all&amp;rdquo; link.&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/lore-links-in-mutt/</guid>
      <pubDate>Wed, 24 Dec 2025 11:21:34 +0000</pubDate>
    </item>
    <item>
      <title>Listening on an ephemeral TCP port</title>
      <link>https://blog.gnoack.org/post/ephemeral-listen</link>
      <description>&lt;h2 id=&#34;the-classic-tcp-clientserver-interaction&#34;&gt;The classic TCP client/server interaction&lt;/h2&gt;&#xA;&lt;p&gt;When a TCP client calls &lt;a href=&#34;https://man.gnoack.org/2/connect&#34;&gt;&lt;em&gt;connect&lt;/em&gt;(2)&lt;/a&gt;, it usually gets assigned a port number from the &lt;em&gt;ephemeral port range&lt;/em&gt; which is not used yet.&lt;/p&gt;&#xA;&lt;p&gt;The server, on the other hand, usually calls &lt;a href=&#34;https://man.gnoack.org/2/bind&#34;&gt;&lt;em&gt;bind&lt;/em&gt;(2)&lt;/a&gt;&#xA;to set the port that it will listen on.&lt;/p&gt;&#xA;&lt;div id=&#39;pikchr-0&#39; class=&#39;pikchr&#39;&gt;&#xA;&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:609px&#39;&gt;&#xA;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 609.754 432.72&#34;&gt;&#xA;&lt;text x=&#34;459&#34; y=&#34;12.24&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;Server&lt;/text&gt;&#xA;&lt;polygon points=&#34;459,56.16 454.68,44.64 463.32,44.64&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M459,27.36L459,50.4&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M410.4,84.96L507.6,84.96L507.6,56.16L410.4,56.16Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;459&#34; y=&#34;70.56&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;socket()&lt;/text&gt;&#xA;&lt;polygon points=&#34;459,113.76 454.68,102.24 463.32,102.24&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M459,84.96L459,108&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M410.4,142.56L507.6,142.56L507.6,113.76L410.4,113.76Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;459&#34; y=&#34;128.16&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;bind()&lt;/text&gt;&#xA;&lt;polygon points=&#34;459,171.36 454.68,159.84 463.32,159.84&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M459,142.56L459,165.6&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M410.4,200.16L507.6,200.16L507.6,171.36L410.4,171.36Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;459&#34; y=&#34;185.76&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;listen()&lt;/text&gt;&#xA;&lt;polygon points=&#34;459,228.96 454.68,217.44 463.32,217.44&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M459,200.16L459,223.2&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M410.4,257.76L507.6,257.76L507.6,228.96L410.4,228.96Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;459&#34; y=&#34;243.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;accept()&lt;/text&gt;&#xA;&lt;polygon points=&#34;459,286.56 454.68,275.04 463.32,275.04&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M459,257.76L459,280.8&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M410.4,315.36L507.6,315.36L507.6,286.56L410.4,286.56Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;459&#34; y=&#34;300.96&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;recv()&lt;/text&gt;&#xA;&lt;polygon points=&#34;459,344.16 454.68,332.64 463.32,332.64&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M459,315.36L459,338.4&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M410.4,372.96L507.6,372.96L507.6,344.16L410.4,344.16Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;459&#34; y=&#34;358.56&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;send()&lt;/text&gt;&#xA;&lt;polygon points=&#34;459,401.76 454.68,390.24 463.32,390.24&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M459,372.96L459,396&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M410.4,430.56L507.6,430.56L507.6,401.76L410.4,401.76Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;459&#34; y=&#34;416.16&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;close()&lt;/text&gt;&#xA;&lt;text x=&#34;245.16&#34; y=&#34;12.24&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;Client&lt;/text&gt;&#xA;&lt;polygon points=&#34;245.16,56.16 240.84,44.64 249.48,44.64&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M245.16,27.36L245.16,50.4&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M196.56,84.96L293.76,84.96L293.76,56.16L196.56,56.16Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;245.16&#34; y=&#34;70.56&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;socket()&lt;/text&gt;&#xA;&lt;polygon points=&#34;245.16,228.96 240.84,217.44 249.48,217.44&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M245.16,84.96L245.16,223.2&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M196.56,257.76L293.76,257.76L293.76,228.96L196.56,228.96Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;245.16&#34; y=&#34;243.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;connect()&lt;/text&gt;&#xA;&lt;polygon points=&#34;245.16,286.56 240.84,275.04 249.48,275.04&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M245.16,257.76L245.16,280.8&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M196.56,315.36L293.76,315.36L293.76,286.56L196.56,286.56Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;245.16&#34; y=&#34;300.96&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;send()&lt;/text&gt;&#xA;&lt;polygon points=&#34;245.16,344.16 240.84,332.64 249.48,332.64&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M245.16,315.36L245.16,338.4&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M196.56,372.96L293.76,372.96L293.76,344.16L196.56,344.16Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;245.16&#34; y=&#34;358.56&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;recv()&lt;/text&gt;&#xA;&lt;polygon points=&#34;245.16,401.76 240.84,390.24 249.48,390.24&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M245.16,372.96L245.16,396&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M196.56,430.56L293.76,430.56L293.76,401.76L196.56,401.76Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;245.16&#34; y=&#34;416.16&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;close()&lt;/text&gt;&#xA;&lt;polygon points=&#34;293.76,243.36 305.28,239.04 305.28,247.68&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;polygon points=&#34;410.4,243.36 398.88,247.68 398.88,239.04&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M299.52,243.36L404.64,243.36&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:7.2,7.2;&#34; /&gt;&#xA;&lt;text x=&#34;352.08&#34; y=&#34;231.66&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;Rendezvous&lt;/text&gt;&#xA;&lt;polygon points=&#34;410.4,300.96 398.88,305.28 398.88,296.64&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M293.76,300.96L404.64,300.96&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:7.2,7.2;&#34; /&gt;&#xA;&lt;polygon points=&#34;293.76,358.56 305.28,354.24 305.28,362.88&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M410.4,358.56L299.52,358.56&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:7.2,7.2;&#34; /&gt;&#xA;&lt;path d=&#34;M182.16,387.36L522,387.36L522,272.16L182.16,272.16Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;&#xA;&lt;polygon points=&#34;196.56,243.36 185.04,247.68 185.04,239.04&#34; style=&#34;fill:rgb(255,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M190.8,243.36L110.16,243.36&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(255,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;&#xA;&lt;text x=&#34;153.36&#34; y=&#34;231.66&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(255,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;get port&lt;/text&gt;&#xA;&lt;ellipse cx=&#34;56.16&#34; cy=&#34;243.36&#34; rx=&#34;54&#34; ry=&#34;36&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(255,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;233.28&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(255,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;ephemeral&lt;/text&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;253.44&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(255,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;port range&lt;/text&gt;&#xA;&lt;text x=&#34;507.6&#34; y=&#34;118.08&#34; text-anchor=&#34;start&#34; font-style=&#34;italic&#34; fill=&#34;rgb(255,0,0)&#34; dominant-baseline=&#34;central&#34;&gt; determines&lt;/text&gt;&#xA;&lt;text x=&#34;507.6&#34; y=&#34;138.24&#34; text-anchor=&#34;start&#34; font-style=&#34;italic&#34; fill=&#34;rgb(255,0,0)&#34; dominant-baseline=&#34;central&#34;&gt; port here&lt;/text&gt;&#xA;&lt;/svg&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;h2 id=&#34;some-less-known-fun-facts&#34;&gt;Some less known fun facts&lt;/h2&gt;&#xA;&lt;h3 id=&#34;servers-that-listen-on-random-ports&#34;&gt;Servers that listen on random ports&lt;/h3&gt;&#xA;&lt;p&gt;While a server will usually &lt;a href=&#34;https://man.gnoack.org/2/bind&#34;&gt;&lt;em&gt;bind&lt;/em&gt;(2)&lt;/a&gt; itself to a fixed port number, it can absolutely omit that, and then, when it calls &lt;a href=&#34;https://man.gnoack.org/2/listen&#34;&gt;&lt;em&gt;listen&lt;/em&gt;(2)&lt;/a&gt;, &lt;strong&gt;the server will get an ephemeral port assigned by the kernel&lt;/strong&gt; which it will then listen on.&#xA;(This is similar to setting the bound port number to 0.)&lt;/p&gt;&#xA;&lt;div id=&#39;pikchr-1&#39; class=&#39;pikchr&#39;&gt;&#xA;&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:268px&#39;&gt;&#xA;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 268.69 256.32&#34;&gt;&#xA;&lt;text x=&#34;50.76&#34; y=&#34;12.24&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;Server&lt;/text&gt;&#xA;&lt;polygon points=&#34;50.76,56.16 46.44,44.64 55.08,44.64&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M50.76,27.36L50.76,50.4&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M2.16,84.96L99.36,84.96L99.36,56.16L2.16,56.16Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;50.76&#34; y=&#34;70.56&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;socket()&lt;/text&gt;&#xA;&lt;polygon points=&#34;50.76,113.76 46.44,102.24 55.08,102.24&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M50.76,84.96L50.76,108&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M2.16,142.56L99.36,142.56L99.36,113.76L2.16,113.76Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;50.76&#34; y=&#34;128.16&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;listen()&lt;/text&gt;&#xA;&lt;polygon points=&#34;50.76,171.36 46.44,159.84 55.08,159.84&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M50.76,142.56L50.76,165.6&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M2.16,200.16L99.36,200.16L99.36,171.36L2.16,171.36Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;50.76&#34; y=&#34;185.76&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;accept()&lt;/text&gt;&#xA;&lt;polygon points=&#34;50.76,228.96 46.44,217.44 55.08,217.44&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M50.76,200.16L50.76,223.2&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;50.76&#34; y=&#34;244.08&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;...&lt;/text&gt;&#xA;&lt;polygon points=&#34;50.76,99.36 62.28,95.04 62.28,103.68&#34; style=&#34;fill:rgb(255,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M56.52,99.36L122.76,99.36&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(255,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;197.525&#34; y=&#34;99.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(255,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;bind() not called&lt;/text&gt;&#xA;&lt;/svg&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;h3 id=&#34;clients-that-use-a-specific-port-number&#34;&gt;Clients that use a specific port number&lt;/h3&gt;&#xA;&lt;p&gt;If a client socket uses &lt;a href=&#34;https://man.gnoack.org/2/bind&#34;&gt;&lt;em&gt;bind&lt;/em&gt;(2)&lt;/a&gt; before &lt;a href=&#34;https://man.gnoack.org/2/connect&#34;&gt;&lt;em&gt;connect&lt;/em&gt;(2)&lt;/a&gt;, &lt;strong&gt;the client can enforce using a specific port number for its own side&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;div id=&#39;pikchr-2&#39; class=&#39;pikchr&#39;&gt;&#xA;&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:234px&#39;&gt;&#xA;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 234.23 256.32&#34;&gt;&#xA;&lt;text x=&#34;50.76&#34; y=&#34;12.24&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;Client&lt;/text&gt;&#xA;&lt;polygon points=&#34;50.76,56.16 46.44,44.64 55.08,44.64&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M50.76,27.36L50.76,50.4&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M2.16,84.96L99.36,84.96L99.36,56.16L2.16,56.16Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;50.76&#34; y=&#34;70.56&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;socket()&lt;/text&gt;&#xA;&lt;polygon points=&#34;50.76,113.76 46.44,102.24 55.08,102.24&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M50.76,84.96L50.76,108&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M2.16,142.56L99.36,142.56L99.36,113.76L2.16,113.76Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(255,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;50.76&#34; y=&#34;128.16&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(255,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;bind()&lt;/text&gt;&#xA;&lt;polygon points=&#34;50.76,171.36 46.44,159.84 55.08,159.84&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M50.76,142.56L50.76,165.6&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M2.16,200.16L99.36,200.16L99.36,171.36L2.16,171.36Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;50.76&#34; y=&#34;185.76&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;connect()&lt;/text&gt;&#xA;&lt;polygon points=&#34;50.76,228.96 46.44,217.44 55.08,217.44&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M50.76,200.16L50.76,223.2&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;50.76&#34; y=&#34;244.08&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;...&lt;/text&gt;&#xA;&lt;text x=&#34;99.36&#34; y=&#34;118.08&#34; text-anchor=&#34;start&#34; font-style=&#34;italic&#34; fill=&#34;rgb(255,0,0)&#34; dominant-baseline=&#34;central&#34;&gt; binds the&lt;/text&gt;&#xA;&lt;text x=&#34;99.36&#34; y=&#34;138.24&#34; text-anchor=&#34;start&#34; font-style=&#34;italic&#34; fill=&#34;rgb(255,0,0)&#34; dominant-baseline=&#34;central&#34;&gt; client-side port&lt;/text&gt;&#xA;&lt;/svg&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;h2 id=&#34;reference&#34;&gt;Reference&lt;/h2&gt;&#xA;&lt;p&gt;The best description I found of this is in &lt;a href=&#34;https://man.gnoack.org/7/ip&#34;&gt;&lt;em&gt;ip&lt;/em&gt;(7)&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;blockquote class=&#34;def&#34;&gt;&lt;p&gt;An ephemeral port is allocated to a socket in the following circumstances:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;the port number in a socket address is specified as 0 when calling bind(2);&lt;/li&gt;&#xA;&lt;li&gt;listen(2) is called on a stream socket that was not previously bound;&lt;/li&gt;&#xA;&lt;li&gt;connect(2) was called on a socket that was not previously bound;&lt;/li&gt;&#xA;&lt;li&gt;sendto(2) is called on a datagram socket that was not previously bound.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;So the behaviour of &lt;a href=&#34;https://man.gnoack.org/2/bind&#34;&gt;&lt;em&gt;bind&lt;/em&gt;(2)&lt;/a&gt; actually works the same on both client and server sockets.  It&amp;rsquo;s just in daily use where it only gets used for server sockets.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://lore.kernel.org/linux-security-module/ZoKB7bl41ZOiiXmF@google.com/&#34;&gt;Previous discussion on the kernel mailing lists&lt;/a&gt;&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/ephemeral-listen/</guid>
      <pubDate>Fri, 14 Nov 2025 19:26:44 +0000</pubDate>
    </item>
    <item>
      <title>Integer overflow checking with C23</title>
      <link>https://blog.gnoack.org/post/int_overflow_c23</link>
      <description>&lt;p&gt;While I wasn&amp;rsquo;t looking, &lt;a href=&#34;https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf#page=330&#34;&gt;C23 has standardized checked integer arithmetic functions&lt;/a&gt;, replacing the old &amp;ldquo;&lt;code&gt;__builtin_mul_overflow()&lt;/code&gt;&amp;rdquo; compiler intrinsics that shipped with &lt;a href=&#34;https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html&#34;&gt;GCC&lt;/a&gt; and &lt;a href=&#34;https://clang.llvm.org/docs/LanguageExtensions.html#checked-arithmetic-builtins&#34;&gt;Clang&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdckdint.h&amp;gt;&#xA;bool ckd_add(type1 *result, type2 a, type3 b);&#xA;bool ckd_sub(type1 *result, type2 a, type3 b);&#xA;bool ckd_mul(type1 *result, type2 a, type3 b);&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The operations are performed equivalently to doing them in the mathematically reasonable way (as normal &lt;a href=&#34;https://en.wikipedia.org/wiki/Integer&#34;&gt;integers in ℤ&lt;/a&gt;, not modulo-something), and then truncating them to fit into the &lt;code&gt;*result&lt;/code&gt; integer.&#xA;The function returns &lt;code&gt;true&lt;/code&gt; if the resulting value could not be represented in &lt;code&gt;*result&lt;/code&gt;&amp;rsquo;s integer type.&lt;/p&gt;&#xA;&lt;p&gt;To check for overflow of two integers &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;, define a variable for the calculation result and do:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-good&#34;&gt;int result;&#xA;if (ckd_mul(&amp;amp;result, a, b)) {&#xA;  errx(1, &amp;quot;a * b overflow or wraparound&amp;quot;);&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;These semantics remove having to worry of the unintuitive difference between (undefined) integer overflow and (well-defined) unsigned integer wraparound.&#xA;(The &amp;ldquo;arithmetic&amp;rdquo; ways for checking overflow/wraparound differ substantially for signed and unsigned integers, otherwise.)&lt;/p&gt;&#xA;&lt;p&gt;The feature is available in:&#xA;&lt;a href=&#34;https://gcc.gnu.org/projects/c-status.html#c23&#34;&gt;GCC 14+&lt;/a&gt;,&#xA;&lt;a href=&#34;https://clang.llvm.org/c_status.html#c2x&#34;&gt;Clang 18+&lt;/a&gt;,&#xA;both released in Q2 2024.&lt;/p&gt;&#xA;&lt;h2 id=&#34;further-references&#34;&gt;Further references&lt;/h2&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152052&#34;&gt;Integer section&lt;/a&gt; of the SEI C Coding Standard wiki has some excellent guidance for correct overflow and wraparound checks, also for older compilers.&#xA;Specifically, these sections are:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://wiki.sei.cmu.edu/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap&#34;&gt;INT30-C. Ensure that unsigned integer operations do not wrap&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://wiki.sei.cmu.edu/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow&#34;&gt;INT32-C. Ensure that operations on signed integers do not result in overflow&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.sei.cmu.edu/authors/david-svoboda/&#34;&gt;David Svoboda&lt;/a&gt;,&#xA;who is involved here,&#xA;is the same person who &lt;a href=&#34;https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2683.pdf&#34;&gt;proposed the extension to the C23&#xA;standard&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://gustedt.wordpress.com/2022/12/18/checked-integer-arithmetic-in-the-prospect-of-c23/&#34;&gt;Jens Gustedt&amp;rsquo;s&#xA;Blog&lt;/a&gt;&#xA;has a longer post on the topic as well with more practical examples&#xA;and a discussion of how to emulate the new interface based on the&#xA;older macros that GCC and LLVM offered before C23.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;__builtin_mul_overflow()&lt;/code&gt; macro and friends were introduced in&#xA;&lt;a href=&#34;https://gcc.gnu.org/gcc-5/changes.html&#34;&gt;GCC 5 (2015)&lt;/a&gt;&#xA;and &lt;a href=&#34;https://releases.llvm.org/3.4/tools/clang/docs/ReleaseNotes.html#c-language-changes-in-clang&#34;&gt;Clang 3.4 (2014)&lt;/a&gt;.&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/int_overflow_c23/</guid>
      <pubDate>Sun, 02 Nov 2025 20:48:02 +0100</pubDate>
    </item>
    <item>
      <title>Landlock Your Vibe Coding</title>
      <link>https://blog.gnoack.org/post/landlock-your-vibe-coding</link>
      <description>&lt;img style=&#34;float: right; width: 20%; border-radius: 1em; margin: 0.5em;&#34; src=&#34;https://blog.gnoack.org/images/goodvibesonly.png&#34;&gt;&#xA;&lt;p&gt;We&amp;rsquo;ve all heard the horror stories where an unsandboxed coding agent&#xA;deletes the user&amp;rsquo;s entire home directory.&#xA;As a mitigation,&#xA;many vibe coding tools are now using Docker to contain the agent&amp;rsquo;s actions.&lt;/p&gt;&#xA;&lt;p&gt;Unfortunately, &lt;strong&gt;Docker is not a good tool to keep the vibe coding agents at bay&lt;/strong&gt;.&#xA;To quote &lt;a href=&#34;https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user&#34;&gt;Docker&amp;rsquo;s own documentation&lt;/a&gt; (emphasis mine):&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;The &lt;code&gt;docker&lt;/code&gt; group &lt;strong&gt;grants root-level privileges to the user&lt;/strong&gt;.&#xA;For details on how this impacts security in your system,&#xA;see &lt;a href=&#34;https://docs.docker.com/engine/security/#docker-daemon-attack-surface&#34;&gt;Docker Daemon Attack Surface&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;So while it keeps the agent from doing harm outside of the Docker container,&#xA;installing Docker also removes the security boundary between your normal user and root.&#xA;Docker is not something that your normal user account should have access to.&lt;/p&gt;&#xA;&lt;p&gt;So as a stop-gap measure, for systems where you don&amp;rsquo;t want to install Docker,&#xA;here is a little ad-hoc sandboxing script which runs &lt;a href=&#34;https://github.com/google-gemini/gemini-cli&#34;&gt;Google&amp;rsquo;s &lt;code&gt;gemini-cli&lt;/code&gt;&lt;/a&gt; in a &lt;a href=&#34;https://landlock.io/&#34;&gt;Landlock&lt;/a&gt; sandbox:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;#!/bin/sh&#xA;&#xA;RDIR=execute,read-file,read-dir&#xA;&#xA;# A reasonable subset of write accesses&#xA;RWDIR=$RDIR,write-file,remove-dir,remove-file,make-dir,make-reg,make-sock,make-fifo,make-sym,refer,truncate&#xA;&#xA;if [ &amp;quot;$PWD&amp;quot; = &amp;quot;$HOME&amp;quot; ]; then&#xA;    echo &amp;quot;Run this from your project directory only&amp;quot;&#xA;    exit 1&#xA;fi&#xA;&#xA;mkdir -p $HOME/.gemini  # ensure this exists, no-op if it preexists&#xA;&#xA;setpriv \&#xA;  --landlock-access fs \&#xA;  --landlock-rule path-beneath:$RWDIR:$HOME/.gemini \&#xA;  --landlock-rule path-beneath:$RDIR:/etc \&#xA;  --landlock-rule path-beneath:$RDIR:/bin \&#xA;  --landlock-rule path-beneath:$RDIR:/usr \&#xA;  --landlock-rule path-beneath:$RDIR:/lib \&#xA;  --landlock-rule path-beneath:$RWDIR:$PWD \&#xA;  /usr/bin/gemini&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The tool used here it &lt;a href=&#34;https://man.gnoack.org/1/setpriv&#34;&gt;&lt;em&gt;setpriv&lt;/em&gt;(1)&lt;/a&gt; from the &lt;code&gt;util-linux&lt;/code&gt; package.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Obligatory warning&lt;/strong&gt;:&#xA;This Landlock invocation restricts access to the &lt;strong&gt;file system&lt;/strong&gt;: It can keep an agent from reading your SSH keys and from seeing of modifying the content of your files outside &lt;code&gt;~/.gemini&lt;/code&gt; and the current directory.  &lt;strong&gt;It does not&lt;/strong&gt; restrict access to networking, Unix signals and a variety of other things.  It keeps your files safe, but you still should not store your prod database credentials within the agent&amp;rsquo;s reach.&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/landlock-your-vibe-coding/</guid>
      <pubDate>Sat, 02 Aug 2025 20:08:48 +0200</pubDate>
    </item>
    <item>
      <title>Argument passing adventures</title>
      <link>https://blog.gnoack.org/post/argument-passing-adventures</link>
      <description>&lt;img src=&#34;/images/gnu-mouse-300.png&#34; style=&#34;float: right; margin-left: 0.5em; max-width: 40%;&#34;&gt;&#xA;&lt;p&gt;When I &lt;a href=&#34;https://blog.gnoack.org/post/emacs-mouse-bug/&#34;&gt;posted about the Emacs mouse&#xA;bug&lt;/a&gt; in February, I&#xA;looked into the patch set again, and of course spotted more mistakes.&#xA;&lt;a href=&#34;https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=ee6a44da3c87cf64d67dd02be8c0127a5bf56175&#34;&gt;This&#xA;patch&lt;/a&gt;&#xA;simplifies and corrects some inconsistent logic in where&#xA;&lt;code&gt;CAP_SYS_ADMIN&lt;/code&gt; was required.  The change does not make a difference&#xA;for existing terminal mouse driver programs like GPM or Consolation,&#xA;but it is noteworthy for the coding aspect:&lt;/p&gt;&#xA;&lt;h2 id=&#34;fantastic-new-ways-of-passing-arguments&#34;&gt;Fantastic new ways of passing arguments&lt;/h2&gt;&#xA;&lt;p&gt;In the kernel code, the decision whether to apply &lt;code&gt;CAP_SYS_ADMIN&lt;/code&gt; is&#xA;made by looking at an &amp;ldquo;enum&amp;rdquo; value (&lt;code&gt;sel_mode&lt;/code&gt;) which defines the&#xA;operation to be run, in a struct which also carries arguments:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;struct {&#xA;    char  subcode;&#xA;    short xs, ys, xe, ye;&#xA;    short sel_mode;&#xA;};&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;And in most cases, &lt;code&gt;sel_mode&lt;/code&gt; &lt;em&gt;was&lt;/em&gt; also used like an enum.&lt;/p&gt;&#xA;&lt;p&gt;However, at some point someone added the operation&#xA;&lt;code&gt;TIOCL_SELMOUSEREPORT&lt;/code&gt; and found that it required an additional&#xA;argument.  But the existing argument struct did not have space for it!&#xA;What to do?&lt;/p&gt;&#xA;&lt;p&gt;Instead of implementing the operation with a different argument&#xA;struct, the implementers then presumably figured that it would be&#xA;easier to implement if they re-used the existing struct.  So they made&#xA;&lt;code&gt;TIOCL_SELMOUSEREPORT&lt;/code&gt; the number 16 (in binary: 10000) and then&#xA;&lt;strong&gt;used the lower 4 bits of the same enum as an additional argument&lt;/strong&gt;.&#xA;(It&amp;rsquo;s the 90&amp;rsquo;s.  Go for it!)&lt;/p&gt;&#xA;&lt;p&gt;None of this got documented either (&lt;a href=&#34;https://josvisser.substack.com/p/chaos-is-the-price-of-freedom&#34;&gt;Chaos is the price of&#xA;freedom&lt;/a&gt;),&#xA;so I also ended up submitting documentation for it to the &lt;a href=&#34;https://man.gnoack.org/2const/TIOCLINUX&#34;&gt;TIOCLINUX&#xA;man page&lt;/a&gt;, in the section&#xA;about &lt;code&gt;TIOCLINUX&lt;/code&gt;&amp;rsquo;s &lt;code&gt;TIOCL_SETSEL&lt;/code&gt; subcode (highlight mine):&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;h4 id=&#34;tiocl-selmousereport&#34;&gt;TIOCL_SELMOUSEREPORT&lt;/h4&gt;&#xA;&lt;p&gt;Make the terminal report (&lt;code&gt;xs&lt;/code&gt;, &lt;code&gt;ys&lt;/code&gt;) as the current mouse location&#xA;using the &lt;a href=&#34;https://man.gnoack.org/1/xterm&#34;&gt;xterm(1)&lt;/a&gt; mouse tracking&#xA;protocol (see&#xA;&lt;a href=&#34;https://man.gnoack.org/4/console_codes&#34;&gt;console_codes(4)&lt;/a&gt;).  &lt;strong&gt;The&#xA;lower 4 bits of &lt;code&gt;sel_mode&lt;/code&gt; (&lt;code&gt;TIOCL_SELBUTTONMASK&lt;/code&gt;) indicate the&#xA;desired button press and modifier key information for the mouse&#xA;event.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;[&amp;hellip;]&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;All of these features are luckily highly obscure and seldomly looked&#xA;at &amp;ndash; I really hope that no one will actually need this documentation&#xA;again, but if they do, it&amp;rsquo;s documented now.&lt;/p&gt;&#xA;&lt;h2 id=&#34;whats-the-takeaway-here&#34;&gt;What&amp;rsquo;s the takeaway here?&lt;/h2&gt;&#xA;&lt;p&gt;Admittedly, I should have read the kernel code better and should not&#xA;have tripped over this.  But also, in my defense, people are trained&#xA;to recognize conventional programming patterns.  If code looks&#xA;conventional on the surface but deviates in surprising ways, it&#xA;becomes easy to miss.  Don&amp;rsquo;t do this.&lt;/p&gt;&#xA;&lt;p&gt;Along the way I also &lt;a href=&#34;https://wiki.gnoack.org/TerminalMouseSupport&#34;&gt;wrote up my understanding of Linux&amp;rsquo;s terminal&#xA;mouse support&lt;/a&gt;.  (I&#xA;should note that I am not a terminal driver expert, and it&amp;rsquo;s possible&#xA;that I am misunderstanding parts of it.)&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=ee6a44da3c87cf64d67dd02be8c0127a5bf56175&#34;&gt;The&#xA;patch&lt;/a&gt;&#xA;is now in all stable kernels (6.12.26+, 6.14.5+).  Versions before 6.7&#xA;are unaffected.&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/argument-passing-adventures/</guid>
      <pubDate>Fri, 02 May 2025 13:54:24 +0200</pubDate>
    </item>
    <item>
      <title>I broke Emacs mouse support on the console</title>
      <link>https://blog.gnoack.org/post/emacs-mouse-bug</link>
      <description>&lt;img src=&#34;/images/gnu-mouse-300.png&#34; style=&#34;float: right; margin-left: 0.5em; max-width: 40%;&#34;&gt;&#xA;&lt;p&gt;I accidentally broke Emacs mouse support on the Linux console. o_O&lt;/p&gt;&#xA;&lt;p&gt;The TIOCLINUX patch for disabling dangerous IOCTLs for the Linux&#xA;console driver (&lt;a href=&#34;https://wiki.gnoack.org/TiocstiTioclinuxSecurityProblems&#34;&gt;background discussed on the&#xA;Wiki&lt;/a&gt;) ended&#xA;up accidentally making the mouse cursor invisible on the Linux console&#xA;(the proper text mode one, not xterm).&lt;/p&gt;&#xA;&lt;p&gt;I apologize for breaking this. We luckily found a patch for it and it&#xA;is now rolling out to stable Linux kernels.&lt;/p&gt;&#xA;&lt;p&gt;If your mouse does not work as expected in Emacs on the Linux console,&#xA;please update your kernel to a newer release.&lt;/p&gt;&#xA;&lt;p&gt;It boggles me that this managed to slip through the cracks in the&#xA;initial review, after we had done such an exhaustive search for&#xA;remaining users in Debian code search.  Lesson learned.&lt;/p&gt;&#xA;&lt;h2 id=&#34;references&#34;&gt;References&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://lore.kernel.org/all/ee3ec63269b43b34e1c90dd8c9743bf8@finder.org/&#34;&gt;GPM &amp;amp; Emacs broken in Linux 6.7&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://lists.gnu.org/archive/html/bug-gnu-emacs/2024-11/msg00275.html&#34;&gt;Emacs bug 74220 - Invisible cursor&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://wiki.gnoack.org/TiocstiTioclinuxSecurityProblems&#34;&gt;Longer Wiki description about the patch that broke it&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/emacs-mouse-bug/</guid>
      <pubDate>Wed, 12 Feb 2025 17:11:09 +0100</pubDate>
    </item>
    <item>
      <title>Git without a hosted platform</title>
      <link>https://blog.gnoack.org/post/git-over-ssh</link>
      <description>&lt;p&gt;People have apparently started believing that in order to use git,&#xA;you&amp;rsquo;d have to also have to host the project on Github or Gitlab:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A few weeks ago, a friend told me that he keeps &lt;a href=&#34;https://www.passwordstore.org/&#34;&gt;his &lt;code&gt;pass&lt;/code&gt; password repository&lt;/a&gt; on Github.&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://beej.us/guide/bggit/&#34;&gt;Beej wrote a guide on git&lt;/a&gt; and the Github workflow is very prominent in it&lt;/li&gt;&#xA;&lt;li&gt;I came home from FOSDEM with a Github and a Gitlab sticker, but not with one for &lt;code&gt;git send-email&lt;/code&gt; or cgit.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I feel that is is underreported that&#xA;&lt;strong&gt;you can easily host Git repos on a normal Unix account&lt;/strong&gt;.&#xA;I use this all the time myself for my personal projects &amp;ndash;&#xA;I maintain far more repositories locally over SSH than I expose on hosted platforms.&#xA;This is not visible on the public internet,&#xA;but maybe that makes it especially mention-worthy.&lt;/p&gt;&#xA;&lt;h2 id=&#34;how-its-done&#34;&gt;How it&amp;rsquo;s done&lt;/h2&gt;&#xA;&lt;p&gt;All you need is an account on a Unix/Linux machine, which you can reach over SSH.&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;On the remote side, set up the repo:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;mkdir -p ~/repos/foobar.git&#xA;cd ~/repos/foobar.git&#xA;git init --bare&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;On the local side, set up the remote:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;git remote add foobar user@hostname:repos/foobar.git&#xA;git push --set-upstream foobar main&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;There is not much more to it. Now you can push and pull.&lt;/p&gt;&#xA;&lt;p&gt;A more detailed description that also covers SSH keys can be found in the &lt;a href=&#34;https://git-scm.com/book/en/v2/Git-on-the-Server-Setting-Up-the-Server&#34;&gt;Git Book&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-if-i-need-more&#34;&gt;What if I need more?&lt;/h2&gt;&#xA;&lt;img src=&#34;/images/git-send-email-300.png&#34; style=&#34;float: right; border: 1px solid black; margin-left: 0.5em; max-width: 40%;&#34;&gt;&#xA;&lt;p&gt;The approach scales and extends to bigger endeavors as well.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Web UI:&lt;/strong&gt; You can set up &lt;a href=&#34;https://git.zx2c4.com/cgit/about/&#34;&gt;cgit&lt;/a&gt; on a web server to render your repositories.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Code review:&lt;/strong&gt; Some projects do code reviews over &lt;a href=&#34;https://git-send-email.io/&#34;&gt;&lt;code&gt;git send-email&lt;/code&gt;&lt;/a&gt;.&#xA;The Linux kernel is known for this and scales up to thousands of developers.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;If a project grows and you want to work with people who can&amp;rsquo;t wrap their heads around this,&#xA;you can still fall back to a hosted platform after the fact and push your repository there later.&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/git-over-ssh/</guid>
      <pubDate>Wed, 05 Feb 2025 21:16:03 +0100</pubDate>
    </item>
    <item>
      <title>Dan Bernstein on sandboxing</title>
      <link>https://blog.gnoack.org/post/djb-sandboxing</link>
      <description>&lt;p&gt;Thoughts on sandboxing, found via &lt;a href=&#34;http://www.aaronsw.com/weblog/001502&#34;&gt;Aaron Swartz&amp;rsquo;s&#xA;weblog&lt;/a&gt;, who in turn found it in&#xA;&lt;a href=&#34;https://cr.yp.to/cv/activities-20050107.pdf&#34;&gt;a writeup about Dan Bernstein&amp;rsquo;s 2005 research&#xA;activities&lt;/a&gt; (at the end):&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;The software installed on my newest home computer contains 78&#xA;million lines of C and C++ source code. Presumably there are&#xA;hundreds of thousands of bugs in this code. Removing all of those&#xA;bugs would be quite expensive. Fortunately, there’s a less expensive&#xA;way to eliminate most security problems.&lt;/p&gt;&#xA;&lt;p&gt;Consider, for example, a compressed music track. The UNIX &lt;code&gt;ogg123&lt;/code&gt;&#xA;program and underlying libraries contain 50000 lines of code whose&#xA;sole purpose is to read a compressed music track in Ogg Vorbis&#xA;format and write an uncompressed music track in wave format.&lt;/p&gt;&#xA;&lt;p&gt;UNIX makes it possible (though unnecessarily difficult) to build a&#xA;&lt;code&gt;safeogg&lt;/code&gt; program that does the same conversion &lt;em&gt;and that has no&#xA;other power over the system&lt;/em&gt;. Bugs in the 50000 lines of code are&#xA;then irrelevant to security: if the input is from an attacker who&#xA;seizes control of &lt;code&gt;safeogg&lt;/code&gt;, the most the attacker can do is write&#xA;arbitrary output, which is what the input source was authorized to&#xA;do anyway.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;I&amp;rsquo;m sharing this here because much of the reasoning behind Landlock&#xA;traces its roots back to the same train of thoughts (and also because&#xA;Dan Bernstein lais down the reasoning very nicely).&lt;/p&gt;&#xA;&lt;h2 id=&#34;choice-of-sandboxing-mechanisms&#34;&gt;Choice of sandboxing mechanisms&lt;/h2&gt;&#xA;&lt;p&gt;This is 2005, so the UNIX mechanisms that he suggests for sandboxing&#xA;are:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://man.gnoack.org/2/chroot&#34;&gt;&lt;em&gt;chroot&lt;/em&gt;(2)&lt;/a&gt; to limit access to the filesystem (&lt;em&gt;requires root, or &lt;code&gt;CAP_SYS_CHROOT&lt;/code&gt; on Linux&lt;/em&gt;)&lt;/li&gt;&#xA;&lt;li&gt;using a temporary unique UID to limit access to other processes (&lt;em&gt;requires root&lt;/em&gt;)&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://man.gnoack.org/2/setrlimit&#34;&gt;&lt;em&gt;setrlimit&lt;/em&gt;(2)&lt;/a&gt; with a hard &lt;code&gt;RLIMIT_NOFILE&lt;/code&gt; of 0 to limit access to the network&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://man.gnoack.org/2/setrlimit&#34;&gt;&lt;em&gt;setrlimit&lt;/em&gt;(2)&lt;/a&gt; with other resource limits to limit RAM resource use&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;(Unfortunately, some of these require higher privileges than what&#xA;normal programs run as, a property that these mechanisms also share&#xA;with classic Linux Security modules like AppArmor and SELinux.)&lt;/p&gt;&#xA;&lt;p&gt;One thing where Landlock&amp;rsquo;s approach differs slightly is that we&#xA;believe that the mechanisms for sandboxing should be available to&#xA;unprivileged processes so that they become maximally useful &amp;ndash;&#xA;software authors for general purpose software generally can not expect&#xA;that their software runs with high privileges, and neither should they&#xA;&amp;ndash; it is absurd if a process needs higher privileges in order to drop&#xA;privileges. (Seccomp was an attempt at a Sandboxing mechanism that did&#xA;not require higher privileges, but &lt;a href=&#34;https://blog.gnoack.org/post/pledge-on-linux/&#34;&gt;Seccomp had other practical&#xA;issues&lt;/a&gt;).&lt;/p&gt;&#xA;&lt;h2 id=&#34;sandboxing-should-be-a-developer-task&#34;&gt;Sandboxing should be a developer task&lt;/h2&gt;&#xA;&lt;p&gt;But the overlap to Landlock&amp;rsquo;s approach is very large &amp;ndash; especially&#xA;when it comes to the idea that the use of the sandboxing mechanism&#xA;should be integrated into a program&amp;rsquo;s design: It becomes the&#xA;programmer&amp;rsquo;s responsibility to design the sandbox, and this results in&#xA;narrower sandboxes:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;I should emphasize here that there’s a fundamental difference&#xA;between this project and typical sandboxing projects described in&#xA;the literature. The goal of a typical sandboxing project is to apply&#xA;as many restrictions as possible to a program while receiving no&#xA;help from the programmer; the problem is that this doesn’t stop all&#xA;attacks.&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; In contrast, I insist on an extreme sandbox&#xA;guaranteeing complete security, and I then ask how the programmer’s&#xA;time can be minimized.  As in Section 1, programs are not static&#xA;objects; the programmer cooperates with the sandboxing tools.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h2 id=&#34;networking&#34;&gt;Networking&lt;/h2&gt;&#xA;&lt;p&gt;Related to that, Dan Bernstein has also made the proposal in the past&#xA;that it should be possible to &lt;a href=&#34;https://cr.yp.to/unix/disablenetwork.html&#34;&gt;disable the&#xA;network&lt;/a&gt; with a dedicated&#xA;&lt;code&gt;disablenetwork(void)&lt;/code&gt; function.&lt;/p&gt;&#xA;&lt;p&gt;In 2009-2010, Michael Stone &lt;a href=&#34;https://lore.kernel.org/all/20091227010441.GA12077@heat/&#34;&gt;sent a Linux patchset for&#xA;that&lt;/a&gt;. That&#xA;patchset unfortunately did not make it, but it will hopefully&#xA;eventually be possible with Landlock! &amp;ndash; Mikhail Ivanov&amp;rsquo;s &lt;a href=&#34;https://lore.kernel.org/all/20240904104824.1844082-1-ivanov.mikhail1@huawei-partners.com/&#34;&gt;&amp;ldquo;Support&#xA;socket access-control&amp;rdquo; patch&#xA;set&lt;/a&gt;&#xA;for Landlock should make it possible to forbid new network connections&#xA;in most cases.  (There are tiny exceptions; for the details, see &lt;a href=&#34;https://blog.gnoack.org/post/landlock-ioctl-talk/&#34;&gt;my&#xA;presentation on it&lt;/a&gt;&#xA;starting around minute 34.)&lt;/p&gt;&#xA;&lt;p&gt;I continue to be very excited for this feature to land.  It&amp;rsquo;ll let&#xA;users define reasonably detailed policies for what kinds of networking&#xA;you still want to use, but one of the largest use cases continues to&#xA;be the case where a program absolutely does not want to do &lt;em&gt;any&lt;/em&gt;&#xA;networking.&lt;/p&gt;&#xA;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;I expect this strategy to produce invulnerable computer systems:&#xA;restructure programs to put almost all code into extreme sandboxes;&#xA;eliminate bugs in the small volume of remaining code. I won’t be&#xA;satisfied until I’ve put the entire security industry out of work.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;We&amp;rsquo;re getting there. 🚀&lt;/p&gt;&#xA;&lt;p&gt;Again, the full writeup from 2005 is available at&#xA;&lt;a href=&#34;https://cr.yp.to/cv/activities-20050107.pdf&#34;&gt;https://cr.yp.to/cv/activities-20050107.pdf&lt;/a&gt; and worth a read.&lt;/p&gt;&#xA;&lt;img src=&#34;/images/sandbox.png&#34;/&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.usenix.org/publications/library/proceedings/sec96/goldberg.html&#34;&gt;https://www.usenix.org/publications/library/proceedings/sec96/goldberg.html&lt;/a&gt;, for example, described a sandboxing tool that applied some restrictions to Netscape’s “DNS helper” program. The subsequently discovered libresolv bug was a security hole in that program despite the sandbox. Imposing heavier restrictions would have meant changing the program.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/djb-sandboxing/</guid>
      <pubDate>Thu, 23 Jan 2025 22:32:27 +0100</pubDate>
    </item>
    <item>
      <title>Upcoming conferences 2025 Q1</title>
      <link>https://blog.gnoack.org/post/upcoming-conferences-2025q1</link>
      <description>&lt;p&gt;I will be attending the following conferences:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://vintagecomputerfestival.ch/&#34;&gt;Vintage Computer Festival Zurich&lt;/a&gt;, January 18-19, 2025&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://fosdem.org/2025/&#34;&gt;FOSDEM 2025&lt;/a&gt;, February 1-2, 2025&#xA;&lt;ul&gt;&#xA;&lt;li&gt;I am &lt;a href=&#34;https://wiki.gnoack.org/FosdemTwentyFive&#34;&gt;collecting a few interesting talks over on the wiki&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;Obligatory Landlock talk: &lt;a href=&#34;https://fosdem.org/2025/schedule/event/fosdem-2025-6071-sandbox-ids-with-landlock/&#34;&gt;Sandbox IDs with Landlock&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;We have Landlock stickers this time :)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;If you happen to be at one of these venues,&#xA;if you are interested in sandboxing,&#xA;or if you just want to chat,&#xA;let me know via email. :)&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/upcoming-conferences-2025q1/</guid>
      <pubDate>Fri, 17 Jan 2025 07:44:45 +0100</pubDate>
    </item>
    <item>
      <title>Talk: Update on Landlock: IOCTL support</title>
      <link>https://blog.gnoack.org/post/landlock-ioctl-talk</link>
      <description>&lt;p&gt;📢 I gave a talk about the recent changes in Landlock and its new&#xA;&lt;a href=&#34;https://wiki.gnoack.org/LandlockIoctlControl&#34;&gt;support for restricting IOCTL&#xA;usage&lt;/a&gt; at the Linux&#xA;Security Summit Europe 2024 in Vienna:&lt;/p&gt;&#xA;&lt;iframe width=&#34;560&#34; height=&#34;315&#34; src=&#34;https://www.youtube-nocookie.com/embed/K2onopkMhuM?si=cywowLOp4-jH-8RB&#34; title=&#34;YouTube video player&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; allowfullscreen&gt;&lt;/iframe&gt;&#xA;&lt;p&gt;🌍 &lt;a href=&#34;https://sched.co/1ebVW&#34;&gt;Talk page&lt;/a&gt;&#xA;| 🎥 &lt;a href=&#34;https://www.youtube.com/watch?v=K2onopkMhuM&#34;&gt;Video on YouTube&lt;/a&gt;&#xA;| 😎 &lt;a href=&#34;https://github.com/landlock-lsm/landlock-logo&#34;&gt;We have stickers!&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;talk-summary&#34;&gt;Talk Summary&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;The Landlock security module lets Linux processes restrict what they&#xA;can do and puts developers in charge of defining appropriate&#xA;sandboxing policies for their programs. We will give a brief&#xA;overview over Landlock’s current features, recent developments, and&#xA;talk about what is next. We will discuss in more detail Landlock’s&#xA;new support for restricting the use of IOCTL and the design&#xA;considerations and trade-offs that went into it.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h2 id=&#34;in-other-news&#34;&gt;In other news&lt;/h2&gt;&#xA;&lt;p&gt;I finally took the time to finish up the &lt;a href=&#34;https://wiki.gnoack.org/LandlockFileSystemCompositionModel&#34;&gt;mathematical writeup of how&#xA;Landlock&amp;rsquo;s file system access rights are&#xA;composed&lt;/a&gt;&#xA;on the wiki.  All of this should be obvious from the documentation,&#xA;but it can still be helpful to have a mathematical model to check&#xA;against.&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/landlock-ioctl-talk/</guid>
      <pubDate>Sun, 13 Oct 2024 11:15:42 +0200</pubDate>
    </item>
    <item>
      <title>Git: Multirepo patch set</title>
      <link>https://blog.gnoack.org/post/git-multirepo-patch-set</link>
      <description>&lt;p&gt;In the context of &lt;a href=&#34;https://lwn.net/Articles/989215/&#34;&gt;Alejandro Colomar stepping down as a man-pages maintainer&lt;/a&gt; :(, &lt;a href=&#34;https://lwn.net/Articles/989398/&#34;&gt;I learned from him&lt;/a&gt; that&#xA;it is possible with &lt;code&gt;git&lt;/code&gt; to create an email patch set that spans multiple target repositories.&#xA;Specifically, he &lt;a href=&#34;https://lore.kernel.org/linux-man/CAEf4BzZzE94QUdhWPmrMzRBRLa=nm86Mdm5vow688jKq3HzJeA@mail.gmail.com/T/#t&#34;&gt;pointed to a review thread by Jiri Olsa&lt;/a&gt; where this was done, and whose outline takes a similar shape to this (simplified):&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;[PATCH proj v3 0/3]&lt;/strong&gt; foobar: Add transmogrifier&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;[PATCH proj v3 1/3]&lt;/strong&gt; foobar: Prepare flux compensator&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;[PATCH proj v3 2/3]&lt;/strong&gt; foobar: Add transmogrifier feature&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;[PATCH man v3 3/3]&lt;/strong&gt; foobar.1: Document transmogrification&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Other than in normal review threads, &lt;em&gt;every mail subject is prefixed with an additional tag here&lt;/em&gt;, to indicate which project it belongs to.&lt;/p&gt;&#xA;&lt;p&gt;It was not obvious to me how to best achieve it with the existing tools, so I attempted to reconstruct how he had done it, and ended up with the workflow that I will describe below.&#xA;&lt;a href=&#34;https://lore.kernel.org/all/Zt__OKtOj8AZGy4X@krava/&#34;&gt;This is not the same workflow that Jiri Olsa has been using&lt;/a&gt; after all, but it&amp;rsquo;s close, and unusual enough that it&amp;rsquo;s maybe worth documenting here.&lt;/p&gt;&#xA;&lt;h2 id=&#34;1-pull-both-original-repositories-in-the-same-local-repository&#34;&gt;1. Pull both original repositories in the same local repository&lt;/h2&gt;&#xA;&lt;p&gt;We first make sure that all necessary commits are stored in the same local repository, by pulling in a second remote repository with &lt;code&gt;git fetch&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;This is unusual, but it is possible.  As a result, your local repository&#xA;contains two unrelated commit histories, for instance one for the linux kernel&#xA;and one for the man pages:&lt;/p&gt;&#xA;&lt;div id=&#39;pikchr-0&#39; class=&#39;pikchr&#39;&gt;&#xA;&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:670px&#39;&gt;&#xA;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 670.32 211.68&#34;&gt;&#xA;&lt;path d=&#34;M155.16,189.36L515.16,189.36A7.2 7.2 0 0 0 522.36 182.16L522.36,9.36A7.2 7.2 0 0 0 515.16 2.16L155.16,2.16A7.2 7.2 0 0 0 147.96 9.36L147.96,182.16A7.2 7.2 0 0 0 155.16 189.36Z&#34;  style=&#34;fill:none;stroke-width:1.4472;stroke:rgb(0,0,0);stroke-dasharray:7.2,7.2;&#34; /&gt;&#xA;&lt;circle cx=&#34;189.051&#34; cy=&#34;72.0512&#34; r=&#34;14.4&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M203.451,72.0512L228.651,72.0512&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M228.651,72.0512L253.851,72.0512&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;&#xA;&lt;path d=&#34;M253.851,72.0512L279.051,72.0512&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;circle cx=&#34;293.451&#34; cy=&#34;72.0512&#34; r=&#34;14.4&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M293.451,57.6512L293.451,28.8512&#34;  style=&#34;fill:none;stroke-width:1.4472;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M212.451,39.6512L293.451,39.6512L293.451,18.0512L212.451,18.0512Z&#34;  style=&#34;fill:none;stroke-width:1.4472;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;252.951&#34; y=&#34;28.8512&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;linux-base&lt;/text&gt;&#xA;&lt;path d=&#34;M307.851,72.0512L333.051,72.0512&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;circle cx=&#34;347.451&#34; cy=&#34;72.0512&#34; r=&#34;14.4&#34;  style=&#34;fill:rgb(255,239,213);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M361.851,72.0512L387.051,72.0512&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;circle cx=&#34;401.451&#34; cy=&#34;72.0512&#34; r=&#34;14.4&#34;  style=&#34;fill:rgb(255,239,213);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M401.451,57.6512L401.451,28.8512&#34;  style=&#34;fill:none;stroke-width:1.4472;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M401.451,39.6512L498.651,39.6512L498.651,18.0512L401.451,18.0512Z&#34;  style=&#34;fill:none;stroke-width:1.4472;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;450.051&#34; y=&#34;28.8512&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;linux-feature&lt;/text&gt;&#xA;&lt;circle cx=&#34;189.051&#34; cy=&#34;158.451&#34; r=&#34;14.4&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M203.451,158.451L228.651,158.451&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M228.651,158.451L253.851,158.451&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;&#xA;&lt;path d=&#34;M253.851,158.451L279.051,158.451&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;circle cx=&#34;293.451&#34; cy=&#34;158.451&#34; r=&#34;14.4&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M293.451,144.051L293.451,115.251&#34;  style=&#34;fill:none;stroke-width:1.4472;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M217.851,126.051L293.451,126.051L293.451,104.451L217.851,104.451Z&#34;  style=&#34;fill:none;stroke-width:1.4472;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;255.651&#34; y=&#34;115.251&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;man-base&lt;/text&gt;&#xA;&lt;path d=&#34;M307.851,158.451L333.051,158.451&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;circle cx=&#34;347.451&#34; cy=&#34;158.451&#34; r=&#34;14.4&#34;  style=&#34;fill:rgb(255,239,213);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M347.451,144.051L347.451,115.251&#34;  style=&#34;fill:none;stroke-width:1.4472;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M347.451,126.051L439.251,126.051L439.251,104.451L347.451,104.451Z&#34;  style=&#34;fill:none;stroke-width:1.4472;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;393.351&#34; y=&#34;115.251&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;man-feature&lt;/text&gt;&#xA;&lt;path d=&#34;M522.36,72.0512L560.16,72.0512&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M560.16,46.8512L560.16,97.2512A54 10.8 0 0 0 668.16 97.2512L668.16,46.8512A54 10.8 0 0 0 560.16 46.8512A54 10.8 0 0 0 668.16 46.8512&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;614.16&#34; y=&#34;70.0712&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;linux&lt;/text&gt;&#xA;&lt;text x=&#34;614.16&#34; y=&#34;90.2312&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;origin&lt;/text&gt;&#xA;&lt;path d=&#34;M522.36,158.451L560.16,158.451&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M560.16,133.251L560.16,183.651A54 10.8 0 0 0 668.16 183.651L668.16,133.251A54 10.8 0 0 0 560.16 133.251A54 10.8 0 0 0 668.16 133.251&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;614.16&#34; y=&#34;156.471&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;man-pages&lt;/text&gt;&#xA;&lt;text x=&#34;614.16&#34; y=&#34;176.631&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;origin&lt;/text&gt;&#xA;&lt;polygon points=&#34;147.96,72.0512 136.44,76.3712 136.44,67.7312&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M142.2,72.0512L110.16,72.0512&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M2.16,97.2512L110.16,97.2512L110.16,46.8512L2.16,46.8512Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;61.9712&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;linux&lt;/text&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;82.1312&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;worktree&lt;/text&gt;&#xA;&lt;polygon points=&#34;147.96,158.451 136.44,162.771 136.44,154.131&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M142.2,158.451L110.16,158.451&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M2.16,183.651L110.16,183.651L110.16,133.251L2.16,133.251Z&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;148.371&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;man-pages&lt;/text&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;168.531&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;worktree&lt;/text&gt;&#xA;&lt;text x=&#34;335.16&#34; y=&#34;199.44&#34; text-anchor=&#34;middle&#34; font-style=&#34;italic&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;local repository&lt;/text&gt;&#xA;&lt;/svg&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;You can simplify your life here a bit by using &lt;a href=&#34;https://git-scm.com/docs/git-worktree&#34;&gt;git worktrees&lt;/a&gt; &amp;ndash; with these, your can keep doing your Linux work in a separate directory to your man page work, but still keep all of the changes in the same repository.&lt;/p&gt;&#xA;&lt;p&gt;In the example above, we have prepared two commits in the &lt;em&gt;linux-feature&lt;/em&gt; branch, based on the &lt;em&gt;linux-base&lt;/em&gt; branch from upstream, as well as one commit in the &lt;em&gt;man-feature&lt;/em&gt; branch, based on &lt;em&gt;man-base&lt;/em&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;example&#34;&gt;Example&lt;/h3&gt;&#xA;&lt;p&gt;Starting from two repositories &lt;code&gt;/tmp/git/linux-origin&lt;/code&gt; and &lt;code&gt;/tmp/git/man-origin&lt;/code&gt;, let&amp;rsquo;s fetch both repositories into the same local repository and create a worktree for each:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;gnoack:/tmp/git$ git clone /tmp/git/linux-origin linux&#xA;Cloning into &#39;linux&#39;...&#xA;done.&#xA;gnoack:/tmp/git$ cd linux&#xA;gnoack:/tmp/git/linux(main)$ git tag linux-base&#xA;gnoack:/tmp/git/linux(main)$ git remote add man-origin /tmp/git/man-origin&#xA;gnoack:/tmp/git/linux(main)$ git fetch man-origin&#xA;remote: Enumerating objects: 12, done.&#xA;remote: Counting objects: 100% (12/12), done.&#xA;remote: Compressing objects: 100% (4/4), done.&#xA;remote: Total 12 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)&#xA;Unpacking objects: 100% (12/12), 948 bytes | 948.00 KiB/s, done.&#xA;From /tmp/git/man-origin&#xA; * [new branch]      main       -&amp;gt; man-origin/main&#xA;gnoack:/tmp/git/linux(main)$ git worktree add /tmp/git/man man-origin/main&#xA;Preparing worktree (detached HEAD efbfa45)&#xA;HEAD is now at efbfa45 4&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;We now have a worktree for the man pages at &lt;code&gt;/tmp/git/man&lt;/code&gt; and one for Linux at &lt;code&gt;/tmp/git/linux&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;We now prepare the Linux and man page commits on top of these git repositories in the usual way, and make sure that we create branches for the pristine states called &lt;code&gt;man-base&lt;/code&gt; and &lt;code&gt;linux-base&lt;/code&gt;, and call our work branches &lt;code&gt;man-feature&lt;/code&gt; and &lt;code&gt;linux-feature&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;2-format-a-patch-set-that-spans-two-otherwise-unrelated-branches&#34;&gt;2. Format a patch set that spans two otherwise unrelated branches&lt;/h2&gt;&#xA;&lt;p&gt;Create a giant patch set that spans two branches.&#xA;Indicating the desired commit range by using dotted range notation &lt;em&gt;twice&lt;/em&gt;.&lt;/p&gt;&#xA;&lt;p&gt;This invocation is compatible with common flags like &lt;code&gt;-v3&lt;/code&gt; for the patch set version and &lt;code&gt;--cover-letter&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;We use &lt;code&gt;--subject-prefix&lt;/code&gt; so that the mail subject is additionally qualified with an abbreviation for the main project.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;git format-patch -v3 --cover-letter \&#xA;   --subject-prefix=&amp;quot;PATCH proj&amp;quot;    \&#xA;   linux-base..linux-feature        \&#xA;   man-base..man-feature&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Remember from the &lt;a href=&#34;https://man.gnoack.org/7/gitrevisions&#34;&gt;&lt;em&gt;gitrevisions&lt;/em&gt;(7)&lt;/a&gt; man page that a &lt;em&gt;revision range&lt;/em&gt; in Git parlance is a set of commits, which are not necessarily ordered in a single linear chain.  (Somewhat surprisingly, they are also not all connected here, as you would think from reading the man page.)&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;git format-patch&lt;/code&gt; includes some additional features for controlling the ordering, but in practice it seems that commits are ordered by date if they are not connected.&lt;/p&gt;&#xA;&lt;h2 id=&#34;3-final-hand-editing&#34;&gt;3. Final hand-editing&lt;/h2&gt;&#xA;&lt;p&gt;Hand-edit the subject prefix in the man page commit&amp;rsquo;s email, so that the man page commit stands out among the others for the reviewers.&lt;/p&gt;&#xA;&lt;p&gt;And sure enough, after &lt;code&gt;git send-email&lt;/code&gt;, the mail thread has the expected form (in &lt;a href=&#34;http://mutt.org/&#34;&gt;&lt;code&gt;mutt&lt;/code&gt;&lt;/a&gt;):&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt; [PATCH proj v3 0/3] foobar: Add transmogrifier&#xA; ├─&amp;gt;[PATCH proj v3 1/3] foobar: Prepare flux compensator&#xA; ├─&amp;gt;[PATCH proj v3 2/3] foobar: Add transmogrifier feature&#xA; └─&amp;gt;[PATCH man v3 3/3] foobar.1: Document transmogrification&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/git-multirepo-patch-set/</guid>
      <pubDate>Tue, 10 Sep 2024 21:03:55 +0200</pubDate>
    </item>
    <item>
      <title>Upcoming talk at LSS Europe 2024</title>
      <link>https://blog.gnoack.org/post/landlock-ioctl-talk-ann</link>
      <description>&lt;p&gt;📢 I will give a talk about the recent changes in Landlock and its new&#xA;&lt;a href=&#34;https://wiki.gnoack.org/LandlockIoctlControl&#34;&gt;support for restricting IOCTL&#xA;usage&lt;/a&gt; at the Linux&#xA;Security Summit Europe 2024 in Vienna:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;The Landlock security module lets Linux processes restrict what they&#xA;can do and puts developers in charge of defining appropriate&#xA;sandboxing policies for their programs. We will give a brief&#xA;overview over Landlock’s current features, recent developments, and&#xA;talk about what is next. We will discuss in more detail Landlock’s&#xA;new support for restricting the use of IOCTL and the design&#xA;considerations and trade-offs that went into it.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;🌍 Link: &lt;a href=&#34;https://sched.co/1ebVW&#34;&gt;https://sched.co/1ebVW&lt;/a&gt;&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/landlock-ioctl-talk-ann/</guid>
      <pubDate>Thu, 29 Aug 2024 22:33:24 +0200</pubDate>
    </item>
    <item>
      <title>Landlock IOCTL control in Linux 6.10</title>
      <link>https://blog.gnoack.org/post/landlock-ioctl</link>
      <description>&lt;p&gt;&lt;a href=&#34;https://wiki.gnoack.org/LandlockIoctlSupport&#34;&gt;Landlock&amp;rsquo;s IOCTL support for device&#xA;files&lt;/a&gt; has &lt;a href=&#34;https://lwn.net/Articles/981961/&#34;&gt;landed in&#xA;Linux 6.10&lt;/a&gt; 🚀.&lt;/p&gt;&#xA;&lt;p&gt;I also merged &lt;a href=&#34;https://github.com/landlock-lsm/go-landlock/commit/db0c8d6f1dff28841564d98a9ce2e55d644d6530&#34;&gt;the IOCTL support in the Go-Landlock&#xA;library&lt;/a&gt;,&#xA;so you can easily play around with it already.&lt;/p&gt;&#xA;&lt;p&gt;In other news, I started informally documenting Landlock usage in C on&#xA;&lt;a href=&#34;https://wiki.gnoack.org/UsingLandlock&#34;&gt;my wiki on the LandlockUsage&#xA;page&lt;/a&gt;.&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/landlock-ioctl/</guid>
      <pubDate>Mon, 15 Jul 2024 21:39:21 +0200</pubDate>
    </item>
    <item>
      <title>LLM-generated docs are usually worthless</title>
      <link>https://blog.gnoack.org/post/llm-generated-docs</link>
      <description>&lt;p&gt;This has always been true, but it begs repeating:&lt;/p&gt;&#xA;&lt;blockquote class=&#34;rule&#34;&gt;&lt;p&gt;&lt;strong&gt;Every docstring should provide additional information&lt;/strong&gt;&#xA;about the thing that it is documenting,&#xA;&lt;strong&gt;which is not obvious from the thing&amp;rsquo;s name&lt;/strong&gt; and its type information.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;And the corollary:&lt;/p&gt;&#xA;&lt;blockquote class=&#34;rule&#34;&gt;&lt;p&gt;&lt;strong&gt;If an LLM could generate the same docstring for you&lt;/strong&gt;,&#xA;based on the name and type information alone,&#xA;&lt;strong&gt;then the docstring is not adding any value&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;This applies independent of whether it was actually written by a LLM,&#xA;or whether you yourself just mindlessly filled in the blanks without thinking.&lt;/p&gt;&#xA;&lt;p&gt;Writing a docstring is supposed to make you think.&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/llm-generated-docs/</guid>
      <pubDate>Fri, 01 Mar 2024 09:09:35 +0100</pubDate>
    </item>
    <item>
      <title>opening /proc/self/fd/1 is not the same as dup(1)</title>
      <link>https://blog.gnoack.org/post/proc-fd-is-not-dup</link>
      <description>&lt;ul id=&#34;toc&#34;&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#introduction&#34;&gt;Introduction&lt;/a&gt;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#this-feature-is-mis-documented&#34;&gt;This feature is mis-documented&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#devfd-behave-different-on-other-unixes&#34;&gt;/dev/fd/* behave different on other Unixes&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#part-1-an-experiment&#34;&gt;Part 1: An experiment!&lt;/a&gt;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#duplicating-the-file-descriptor-using-dup2&#34;&gt;Duplicating the file descriptor using dup(2)&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#duplicating-the-file-descriptor-through-proc&#34;&gt;Duplicating the file descriptor through /proc&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#other-file-types&#34;&gt;Other file types&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#tcp-sockets-can-not-be-reopened-through-proc&#34;&gt;TCP Sockets: Can not be reopened through /proc&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#pipes-can-be-reopened-through-proc&#34;&gt;Pipes: Can be reopened through /proc&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#part-2-what-is-really-happening&#34;&gt;Part 2: What is really happening&lt;/a&gt;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#where-did-the-no-open-pointer-come-from&#34;&gt;Where did the no_open pointer come from?&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#summary&#34;&gt;Summary&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;Unix processes have &lt;em&gt;file descriptors&lt;/em&gt; which point to &lt;em&gt;file descriptions&lt;/em&gt; (&lt;code&gt;struct file&lt;/code&gt; in Linux).  Multiple file descriptors can point to the same file description, for instance by duplicating them with &lt;a href=&#34;https://man.gnoack.org/2/dup&#34;&gt;&lt;em&gt;dup&lt;/em&gt;(2)&lt;/a&gt;, or by passing them across process boundaries using &lt;a href=&#34;https://man.gnoack.org/2/fork&#34;&gt;&lt;em&gt;fork&lt;/em&gt;(2)&lt;/a&gt; or UNIX Domain Sockets (&lt;a href=&#34;https://man.gnoack.org/7/unix&#34;&gt;&lt;em&gt;unix&lt;/em&gt;(7)&lt;/a&gt;).&lt;/p&gt;&#xA;&lt;div id=&#39;pikchr-0&#39; class=&#39;pikchr&#39;&gt;&#xA;&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:503px&#39;&gt;&#xA;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 503.785 218.52&#34;&gt;&#xA;&lt;path d=&#34;M2.16,63.36L110.16,63.36L110.16,27.36L2.16,27.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;45.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;0&lt;/text&gt;&#xA;&lt;path d=&#34;M2.16,99.36L110.16,99.36L110.16,63.36L2.16,63.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;81.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;1&lt;/text&gt;&#xA;&lt;path d=&#34;M2.16,135.36L110.16,135.36L110.16,99.36L2.16,99.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;117.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;2&lt;/text&gt;&#xA;&lt;path d=&#34;M2.16,171.36L110.16,171.36L110.16,135.36L2.16,135.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;153.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;3&lt;/text&gt;&#xA;&lt;path d=&#34;M393.625,63.36L501.625,63.36L501.625,27.36L393.625,27.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;447.625&#34; y=&#34;45.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;0&lt;/text&gt;&#xA;&lt;path d=&#34;M393.625,99.36L501.625,99.36L501.625,63.36L393.625,63.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;447.625&#34; y=&#34;81.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;1&lt;/text&gt;&#xA;&lt;path d=&#34;M393.625,135.36L501.625,135.36L501.625,99.36L393.625,99.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;447.625&#34; y=&#34;117.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;2&lt;/text&gt;&#xA;&lt;path d=&#34;M393.625,171.36L501.625,171.36L501.625,135.36L393.625,135.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;447.625&#34; y=&#34;153.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;3&lt;/text&gt;&#xA;&lt;text x=&#34;2.16&#34; y=&#34;12.24&#34; text-anchor=&#34;start&#34; font-style=&#34;italic&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;Process 1:&lt;/text&gt;&#xA;&lt;text x=&#34;393.625&#34; y=&#34;12.24&#34; text-anchor=&#34;start&#34; font-style=&#34;italic&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;Process 2:&lt;/text&gt;&#xA;&lt;path d=&#34;M197.892,180.36L305.892,180.36L305.892,126.36L197.892,126.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;251.892&#34; y=&#34;143.28&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;file&lt;/text&gt;&#xA;&lt;text x=&#34;251.892&#34; y=&#34;163.44&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;description&lt;/text&gt;&#xA;&lt;path d=&#34;M197.892,216.36L305.892,216.36L305.892,180.36L197.892,180.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;251.892&#34; y=&#34;198.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;f_pos&lt;/text&gt;&#xA;&lt;polygon points=&#34;197.892,153.36 186.372,157.68 186.372,149.04&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M110.16,153.36L192.132,153.36&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;&#xA;&lt;polygon points=&#34;305.892,153.36 317.412,149.04 317.412,157.68&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M393.625,153.36L311.652,153.36&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;&#xA;&lt;/svg&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;For a long time, I was under the impression that that was also what happened behind the scenes when opening &lt;code&gt;/dev/fd/${FD}&lt;/code&gt; (a.k.a. &lt;code&gt;/proc/${PID}/fd/${FD}&lt;/code&gt;) on Linux.  I thought I would get a new file descriptor which is also pointing to the same file descrip&lt;em&gt;tion&lt;/em&gt;, similar to if you were calling &lt;code&gt;dup(fd)&lt;/code&gt;.  &lt;strong&gt;This is wrong!&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;this-feature-is-mis-documented&#34;&gt;This feature is mis-documented&lt;/h3&gt;&#xA;&lt;p&gt;The misunderstanding is even documented in my earlier edition of&#xA;&amp;ldquo;&lt;a href=&#34;https://man7.org/tlpi/&#34;&gt;The Linux Programming Interface&lt;/a&gt;&amp;rdquo; (section 5.11)&#xA;(&lt;a href=&#34;https://man7.org/tlpi/errata/index.html#p_107&#34;&gt;but it has been fixed in newer editions&lt;/a&gt;,&#xA;as Michael Kerrisk points out in the comments below):&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Opening one of the files in the /dev/fd directory is equivalent to duplicating the corresponding file descriptor.  Thus, the following statements are equivalent:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bad&#34;&gt;fd = open(&amp;quot;/dev/fd/1&amp;quot;, O_WRONLY);&#xA;fd = dup(1);&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;This is a reasonably simple explanation which is close enough to&#xA;reality for many practical use cases, and which is true on other&#xA;Unixes, but it is not fully accurate on Linux.  (The book is very&#xA;comprehensive and useful nevertheless.)&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://bugzilla.redhat.com/show_bug.cgi?id=10417&#34;&gt;This RedHat bug from&#xA;2000&lt;/a&gt; discusses how&#xA;that behaviour was apparently changed in Linux 1.3.34.  The&#xA;aforementioned equivalence between the &lt;a href=&#34;https://man.gnoack.org/2/open&#34;&gt;&lt;em&gt;open&lt;/em&gt;(2)&lt;/a&gt; and &lt;a href=&#34;https://man.gnoack.org/2/dup&#34;&gt;&lt;em&gt;dup&lt;/em&gt;(2)&lt;/a&gt; calls is&#xA;called the &amp;ldquo;Plan9 semantics&amp;rdquo; there.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://man.gnoack.org/5/proc_pid_fd&#34;&gt;&lt;em&gt;proc_pid_fd&lt;/em&gt;(5)&lt;/a&gt; gives usage examples, but does not go into a lot of&#xA;detail on the exact semantics in the case of &lt;a href=&#34;https://man.gnoack.org/2/open&#34;&gt;&lt;em&gt;open&lt;/em&gt;(2)&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;devfd-behave-different-on-other-unixes&#34;&gt;&lt;code&gt;/dev/fd/*&lt;/code&gt; behave different on other Unixes&lt;/h3&gt;&#xA;&lt;p&gt;On top of that, the behavior is implemented differently on other Unixes.&lt;/p&gt;&#xA;&lt;p&gt;From a FreeBSD 14 box:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;$ ./dup -dup &amp;gt; out; cat out; echo&#xA;1d&#xA;$ ./dup -proc &amp;gt; out; cat out; echo&#xA;1d&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;On FreeBSD, the result of &lt;code&gt;open(&amp;quot;/dev/fd/1&amp;quot;, O_WRONLY);&lt;/code&gt; &lt;em&gt;does&lt;/em&gt; share the same file descrip&lt;em&gt;tion&lt;/em&gt; with the original file descriptor, as if we were calling &lt;code&gt;dup(1)&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;part-1-an-experiment&#34;&gt;Part 1: An experiment!&lt;/h2&gt;&#xA;&lt;p&gt;It turns out, opening &lt;code&gt;/dev/fd/*&lt;/code&gt;, &lt;code&gt;/proc/${PID}/fd/*&lt;/code&gt; or &lt;code&gt;/proc/self/fd/*&lt;/code&gt; (&lt;a href=&#34;https://man.gnoack.org/5/proc_pid_fd&#34;&gt;&lt;em&gt;proc_pid_fd&lt;/em&gt;(5)&lt;/a&gt;) results in a &lt;em&gt;separate&lt;/em&gt; file descrip&lt;em&gt;tion&lt;/em&gt; (&lt;code&gt;struct file&lt;/code&gt;) being allocated for you, but it refers to the same underlying file on disk.&lt;/p&gt;&#xA;&lt;p&gt;You can try it out with the following program:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;$ cat dup.c&#xA;#include &amp;lt;err.h&amp;gt;&#xA;#include &amp;lt;fcntl.h&amp;gt;&#xA;#include &amp;lt;stdio.h&amp;gt;&#xA;#include &amp;lt;string.h&amp;gt;&#xA;#include &amp;lt;unistd.h&amp;gt;&#xA;&#xA;int usage(const char *name) {&#xA;  printf(&amp;quot;Usage: %s [-dup|-proc]\n&amp;quot;, name);&#xA;  return 0;&#xA;}&#xA;&#xA;int main(int argc, char *argv[]) {&#xA;  int fd;&#xA;&#xA;  if (argc != 2) {&#xA;    return usage(argv[0]);&#xA;  }&#xA;&#xA;  if (!strcmp(argv[1], &amp;quot;-dup&amp;quot;)) {&#xA;    fd = dup(1);  // stdout&#xA;    if (fd &amp;lt; 0) {&#xA;      err(1, &amp;quot;dup&amp;quot;);&#xA;    }&#xA;  } else if (!strcmp(argv[1], &amp;quot;-proc&amp;quot;)) {&#xA;    fd = open(&amp;quot;/dev/fd/1&amp;quot;, O_WRONLY);&#xA;    if (fd &amp;lt; 0) {&#xA;      err(1, &amp;quot;open /dev/fd/1&amp;quot;);&#xA;    }&#xA;  } else {&#xA;    return usage(argv[0]);&#xA;  }&#xA;&#xA;  write(1, &amp;quot;1&amp;quot;, 1);&#xA;  &#xA;  write(fd, &amp;quot;d&amp;quot;, 1);&#xA;  close(fd);&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;When we build and run this program, we can see that the behavior of &lt;a href=&#34;https://man.gnoack.org/2/dup&#34;&gt;&lt;em&gt;dup&lt;/em&gt;(2)&lt;/a&gt; and &lt;a href=&#34;https://man.gnoack.org/2/open&#34;&gt;&lt;em&gt;open&lt;/em&gt;(2)&lt;/a&gt; is actually different!&lt;/p&gt;&#xA;&lt;h3 id=&#34;duplicating-the-file-descriptor-using-dup2&#34;&gt;Duplicating the file descriptor using &lt;a href=&#34;https://man.gnoack.org/2/dup&#34;&gt;&lt;em&gt;dup&lt;/em&gt;(2)&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;pre&gt;&lt;code&gt;$ make dup&#xA;cc -Wall -static    dup.c   -o dup&#xA;$ ./dup -dup &amp;gt; out; cat out; echo&#xA;1d&#xA;$&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;In the &lt;a href=&#34;https://man.gnoack.org/2/dup&#34;&gt;&lt;em&gt;dup&lt;/em&gt;(2)&lt;/a&gt; case, the &lt;code&gt;struct file&lt;/code&gt; is actually shared &amp;ndash; both file descriptors refer to the exact same file descrip&lt;em&gt;tion&lt;/em&gt;.  The first &lt;a href=&#34;https://man.gnoack.org/2/write&#34;&gt;&lt;em&gt;write&lt;/em&gt;(2)&lt;/a&gt; updates the file description&amp;rsquo;s file position (&lt;code&gt;f_pos&lt;/code&gt;).  The second &lt;a href=&#34;https://man.gnoack.org/2/write&#34;&gt;&lt;em&gt;write&lt;/em&gt;(2)&lt;/a&gt; uses the exact same file description, so it sees the updated file position, and the byte gets written &lt;em&gt;after&lt;/em&gt; the one that was written before.&lt;/p&gt;&#xA;&lt;div id=&#39;pikchr-1&#39; class=&#39;pikchr&#39;&gt;&#xA;&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:308px&#39;&gt;&#xA;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 308.052 173.52&#34;&gt;&#xA;&lt;path d=&#34;M2.16,63.36L110.16,63.36L110.16,27.36L2.16,27.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;45.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;0&lt;/text&gt;&#xA;&lt;path d=&#34;M2.16,99.36L110.16,99.36L110.16,63.36L2.16,63.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;81.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;1&lt;/text&gt;&#xA;&lt;path d=&#34;M2.16,135.36L110.16,135.36L110.16,99.36L2.16,99.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;117.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;2&lt;/text&gt;&#xA;&lt;path d=&#34;M2.16,171.36L110.16,171.36L110.16,135.36L2.16,135.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;153.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;3&lt;/text&gt;&#xA;&lt;text x=&#34;2.16&#34; y=&#34;12.24&#34; text-anchor=&#34;start&#34; font-style=&#34;italic&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;&#39;dup&#39; process:&lt;/text&gt;&#xA;&lt;path d=&#34;M197.892,135.36L305.892,135.36L305.892,81.36L197.892,81.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;251.892&#34; y=&#34;98.28&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;file&lt;/text&gt;&#xA;&lt;text x=&#34;251.892&#34; y=&#34;118.44&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;description&lt;/text&gt;&#xA;&lt;path d=&#34;M197.892,171.36L305.892,171.36L305.892,135.36L197.892,135.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;251.892&#34; y=&#34;153.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;f_pos&lt;/text&gt;&#xA;&lt;polygon points=&#34;197.892,108.36 185.611,109.1 188.153,100.843&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M110.16,81.36L192.387,106.666&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;&#xA;&lt;polygon points=&#34;197.892,121.86 188.51,129.819 185.59,121.687&#34; style=&#34;fill:rgb(255,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M110.16,153.36L192.471,123.806&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(255,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;&#xA;&lt;text x=&#34;154.026&#34; y=&#34;149.31&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(255,0,0)&#34; transform=&#34;rotate(-19.75051581 154.026,137.61)&#34; dominant-baseline=&#34;central&#34;&gt;dup(2)&lt;/text&gt;&#xA;&lt;/svg&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;h3 id=&#34;duplicating-the-file-descriptor-through-proc&#34;&gt;Duplicating the file descriptor through &lt;code&gt;/proc&lt;/code&gt;&lt;/h3&gt;&#xA;&lt;pre&gt;&lt;code&gt;$ ./dup -proc &amp;gt; out; cat out; echo&#xA;d&#xA;$&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;In the &lt;a href=&#34;https://man.gnoack.org/5/proc_pid_fd&#34;&gt;&lt;em&gt;proc_pid_fd&lt;/em&gt;(5)&lt;/a&gt; case, we see only one byte written to the output file.&#xA;So there are &lt;em&gt;two&lt;/em&gt; &lt;code&gt;struct file&lt;/code&gt;s created &amp;ndash;&#xA;and they use independent positions &lt;code&gt;f_pos&lt;/code&gt; in the file, which are both set to 0 initially.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The first &lt;em&gt;write&lt;/em&gt;(2) through stdout (fd 1) updates the file position from 0 to 1.&lt;/li&gt;&#xA;&lt;li&gt;The second &lt;em&gt;write&lt;/em&gt;(2) uses a separate file description&#xA;and &lt;em&gt;overwrites&lt;/em&gt; the byte that was previously written.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;That&amp;rsquo;s why we can only see &amp;ldquo;&lt;code&gt;d&lt;/code&gt;&amp;rdquo; in the output.&lt;/p&gt;&#xA;&lt;div id=&#39;pikchr-2&#39; class=&#39;pikchr&#39;&gt;&#xA;&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:308px&#39;&gt;&#xA;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 308.052 218.52&#34;&gt;&#xA;&lt;path d=&#34;M2.16,63.36L110.16,63.36L110.16,27.36L2.16,27.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;45.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;0&lt;/text&gt;&#xA;&lt;path d=&#34;M2.16,99.36L110.16,99.36L110.16,63.36L2.16,63.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;81.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;1&lt;/text&gt;&#xA;&lt;path d=&#34;M2.16,135.36L110.16,135.36L110.16,99.36L2.16,99.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;117.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;2&lt;/text&gt;&#xA;&lt;path d=&#34;M2.16,171.36L110.16,171.36L110.16,135.36L2.16,135.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;153.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;3&lt;/text&gt;&#xA;&lt;text x=&#34;2.16&#34; y=&#34;12.24&#34; text-anchor=&#34;start&#34; font-style=&#34;italic&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;&#39;dup&#39; process:&lt;/text&gt;&#xA;&lt;path d=&#34;M197.892,80.0135L305.892,80.0135L305.892,26.0135L197.892,26.0135Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;251.892&#34; y=&#34;42.9335&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;file&lt;/text&gt;&#xA;&lt;text x=&#34;251.892&#34; y=&#34;63.0935&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;description&lt;/text&gt;&#xA;&lt;path d=&#34;M197.892,116.014L305.892,116.014L305.892,80.0135L197.892,80.0135Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;251.892&#34; y=&#34;98.0135&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;f_pos&lt;/text&gt;&#xA;&lt;path d=&#34;M197.892,180.36L305.892,180.36L305.892,126.36L197.892,126.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;251.892&#34; y=&#34;143.28&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;file&lt;/text&gt;&#xA;&lt;text x=&#34;251.892&#34; y=&#34;163.44&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;description&lt;/text&gt;&#xA;&lt;path d=&#34;M197.892,216.36L305.892,216.36L305.892,180.36L197.892,180.36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;251.892&#34; y=&#34;198.36&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;f_pos&lt;/text&gt;&#xA;&lt;polygon points=&#34;197.892,53.0135 188.258,60.6661 185.602,52.4446&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M110.16,81.36L192.411,54.7845&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;&#xA;&lt;polygon points=&#34;197.892,153.36 186.372,157.68 186.372,149.04&#34; style=&#34;fill:rgb(255,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M110.16,153.36L192.132,153.36&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(255,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;&#xA;&lt;text x=&#34;154.026&#34; y=&#34;165.06&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(255,0,0)&#34; transform=&#34;rotate(-0 154.026,153.36)&#34; dominant-baseline=&#34;central&#34;&gt;open(2)&lt;/text&gt;&#xA;&lt;/svg&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;h3 id=&#34;other-file-types&#34;&gt;Other file types&lt;/h3&gt;&#xA;&lt;p&gt;So far, this was a bit confusing.  It&amp;rsquo;s definitely inconsistent with&#xA;the theory that opening &lt;code&gt;/dev/fd/*&lt;/code&gt; does the same as &lt;a href=&#34;https://man.gnoack.org/2/dup&#34;&gt;&lt;em&gt;dup&lt;/em&gt;(2)&lt;/a&gt;.  But&#xA;what happens for other file types than regular files?&lt;/p&gt;&#xA;&lt;h3 id=&#34;tcp-sockets-can-not-be-reopened-through-proc&#34;&gt;TCP Sockets: Can not be reopened through &lt;code&gt;/proc&lt;/code&gt;&lt;/h3&gt;&#xA;&lt;p&gt;You can try this out by redirecting stdout to a socket, using the&#xA;obscure &lt;code&gt;/dev/tcp&lt;/code&gt; extension in bash&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;$ nc -l 9999 &amp;amp;&#xA;[1] 4166&#xA;$ ./dup -proc &amp;gt;/dev/tcp/localhost/9999&#xA;dup: open /dev/fd/1: No such device or address&#xA;[1]+  Done                    nc -l 9999&#xA;$ &#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The error here is &lt;code&gt;ENXIO: No such device or address&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;For sockets, the &lt;code&gt;/proc/self/fd/*&lt;/code&gt; entry is a symlink to a name like &lt;code&gt;socket:[16902]&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;lrwx------ 1 gnoack gnoack 64 Feb 17 23:12 1 -&amp;gt; &#39;socket:[16902]&#39;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h3 id=&#34;pipes-can-be-reopened-through-proc&#34;&gt;Pipes: &lt;em&gt;Can&lt;/em&gt; be reopened through &lt;code&gt;/proc&lt;/code&gt;&lt;/h3&gt;&#xA;&lt;p&gt;However, a pipe &lt;strong&gt;can&lt;/strong&gt; be reopened through &lt;code&gt;/dev/fd/1&lt;/code&gt;, for example like this:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;$ ./dup -proc | cat ; echo&#xA;1d&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&amp;hellip;and this works even though the pipe&amp;rsquo;s symlink looks like this:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;l-wx------ 1 gnoack gnoack 64 Feb 17 23:10 1 -&amp;gt; &#39;pipe:[15895]&#39;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2 id=&#34;part-2-what-is-really-happening&#34;&gt;Part 2: What is really happening&lt;/h2&gt;&#xA;&lt;p&gt;First, let&amp;rsquo;s recall the in-kernel VFS structure:&lt;/p&gt;&#xA;&lt;div id=&#39;pikchr-3&#39; class=&#39;pikchr&#39;&gt;&#xA;&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:652px&#39;&gt;&#xA;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 652.32 337.32&#34;&gt;&#xA;&lt;path d=&#34;M2.16,164.16L110.16,164.16L110.16,128.16L2.16,128.16Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;146.16&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;Process&lt;/text&gt;&#xA;&lt;polygon points=&#34;182.16,146.16 170.64,150.48 170.64,141.84&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M110.16,146.16L176.4,146.16&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;146.16&#34; y=&#34;134.46&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;fd&lt;/text&gt;&#xA;&lt;path d=&#34;M197.16,164.16L275.16,164.16A15 15 0 0 0 290.16 149.16L290.16,143.16A15 15 0 0 0 275.16 128.16L197.16,128.16A15 15 0 0 0 182.16 143.16L182.16,149.16A15 15 0 0 0 197.16 164.16Z&#34;  style=&#34;fill:rgb(255,239,213);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;236.16&#34; y=&#34;146.16&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;file object&lt;/text&gt;&#xA;&lt;polygon points=&#34;362.16,146.16 350.64,150.48 350.64,141.84&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M290.16,146.16L356.4,146.16&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;326.16&#34; y=&#34;134.46&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;f_path&lt;/text&gt;&#xA;&lt;path d=&#34;M362.16,164.16L470.16,164.16L470.16,128.16L362.16,128.16Z&#34;  style=&#34;fill:rgb(255,250,205);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;416.16&#34; y=&#34;146.16&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;path&lt;/text&gt;&#xA;&lt;polygon points=&#34;542.16,146.16 530.64,150.48 530.64,141.84&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M470.16,146.16L536.4,146.16&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;506.16&#34; y=&#34;134.46&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;dentry&lt;/text&gt;&#xA;&lt;path d=&#34;M542.16,164.16L650.16,164.16L650.16,128.16L542.16,128.16Z&#34;  style=&#34;fill:rgb(176,224,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;596.16&#34; y=&#34;146.16&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;dentry&lt;/text&gt;&#xA;&lt;polygon points=&#34;596.16,236.16 591.84,224.64 600.48,224.64&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M596.16,164.16L596.16,230.4&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;596.16&#34; y=&#34;188.46&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; transform=&#34;rotate(90 596.16,200.16)&#34; dominant-baseline=&#34;central&#34;&gt;d_inode&lt;/text&gt;&#xA;&lt;path d=&#34;M557.16,272.16L635.16,272.16A15 15 0 0 0 650.16 257.16L650.16,251.16A15 15 0 0 0 635.16 236.16L557.16,236.16A15 15 0 0 0 542.16 251.16L542.16,257.16A15 15 0 0 0 557.16 272.16Z&#34;  style=&#34;fill:rgb(255,239,213);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;596.16&#34; y=&#34;254.16&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;inode object&lt;/text&gt;&#xA;&lt;polygon points=&#34;470.16,254.16 481.68,249.84 481.68,258.48&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M542.16,254.16L475.92,254.16&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;506.16&#34; y=&#34;242.46&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;i_sb&lt;/text&gt;&#xA;&lt;path d=&#34;M362.16,281.16L470.16,281.16L470.16,227.16L362.16,227.16Z&#34;  style=&#34;fill:rgb(255,160,122);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;416.16&#34; y=&#34;244.08&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;Superblock&lt;/text&gt;&#xA;&lt;text x=&#34;416.16&#34; y=&#34;264.24&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;object&lt;/text&gt;&#xA;&lt;polygon points=&#34;290.16,254.16 301.68,249.84 301.68,258.48&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M362.16,254.16L295.92,254.16&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;&#xA;&lt;polygon points=&#34;290.16,308.16 301.68,303.84 301.68,312.48&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M596.16,272.16L596.16,308.16L295.92,308.16&#34;  style=&#34;fill:none;stroke-width:2.16;stroke-linejoin:round;stroke:rgb(0,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;&#xA;&lt;path d=&#34;M182.16,237.96L182.16,324.36A54 10.8 0 0 0 290.16 324.36L290.16,237.96A54 10.8 0 0 0 182.16 237.96A54 10.8 0 0 0 290.16 237.96&#34;  style=&#34;fill:rgb(219,112,147);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;236.16&#34; y=&#34;279.18&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;Disk&lt;/text&gt;&#xA;&lt;text x=&#34;236.16&#34; y=&#34;299.34&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;file&lt;/text&gt;&#xA;&lt;polygon points=&#34;416.16,56.16 420.48,67.68 411.84,67.68&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M416.16,128.16L416.16,61.92&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;416.16&#34; y=&#34;80.46&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; transform=&#34;rotate(-90 416.16,92.16)&#34; dominant-baseline=&#34;central&#34;&gt;mnt&lt;/text&gt;&#xA;&lt;path d=&#34;M362.16,56.16L470.16,56.16L470.16,2.16L362.16,2.16Z&#34;  style=&#34;fill:rgb(255,215,0);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;416.16&#34; y=&#34;19.08&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;struct&lt;/text&gt;&#xA;&lt;text x=&#34;416.16&#34; y=&#34;39.24&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;vfsmount&lt;/text&gt;&#xA;&lt;text x=&#34;236.16&#34; y=&#34;92.88&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;This is the&lt;/text&gt;&#xA;&lt;text x=&#34;236.16&#34; y=&#34;113.04&#34; text-anchor=&#34;middle&#34; font-style=&#34;italic&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;file description&lt;/text&gt;&#xA;&lt;/svg&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;The following things happen in a sequence:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A user space process calls &lt;code&gt;open(&amp;quot;/proc/self/fd/1&amp;quot;)&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;System call handler:&#xA;&lt;ul&gt;&#xA;&lt;li&gt;parses flags&lt;/li&gt;&#xA;&lt;li&gt;does the path walk, which eventually invokes &lt;code&gt;proc_pid_get_link()&lt;/code&gt;:&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;fs/proc/base.c:proc_pid_get_link()&lt;/code&gt;:&#xA;&lt;ul&gt;&#xA;&lt;li&gt;invokes &lt;code&gt;proc_fd_link()&lt;/code&gt; through a callback&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;fs/proc/fd.c:proc_fd_link()&lt;/code&gt;: looks up the original &lt;code&gt;struct file*&lt;/code&gt; from the target task and &lt;strong&gt;returns the &lt;code&gt;-&amp;gt;f_path&lt;/code&gt;&lt;/strong&gt; that existed on that &lt;code&gt;struct file&lt;/code&gt; (through an output pointer argument).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;invokes &lt;code&gt;nd_jump_link()&lt;/code&gt;, which &lt;strong&gt;sets the result of the path walk in &lt;code&gt;nameidata&lt;/code&gt; to the previously set path!&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;eventually calls &lt;code&gt;path_openat()&lt;/code&gt;.&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;namei.c:path_openat()&lt;/code&gt;: &lt;strong&gt;Always&lt;/strong&gt; allocates a new &lt;code&gt;struct file&lt;/code&gt; with &lt;code&gt;alloc_empty_file()&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;namei.c:do_open()&lt;/code&gt;: calls &lt;code&gt;vfs_open()&lt;/code&gt;, which in turn calls &lt;code&gt;do_dentry_open()&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;open.c:do_dentry_open()&lt;/code&gt;:&#xA;&lt;ul&gt;&#xA;&lt;li&gt;first initializes the file ops from the inode: &lt;code&gt;f-&amp;gt;f_op = fops_get(inode-&amp;gt;i_fop)&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;the calls the &amp;ldquo;open&amp;rdquo; file operation: &lt;code&gt;f-&amp;gt;f_op-&amp;gt;open&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;where-did-the-no-open-pointer-come-from&#34;&gt;Where did the &lt;code&gt;no_open&lt;/code&gt; pointer come from?&lt;/h3&gt;&#xA;&lt;p&gt;For the TCP socket above, &lt;code&gt;f-&amp;gt;f_op-&amp;gt;open&lt;/code&gt; is set to the &lt;code&gt;no_open&lt;/code&gt; function, which unconditionally returns &lt;code&gt;ENXIO&lt;/code&gt;.  So that socket can&amp;rsquo;t be reopened through &lt;code&gt;/proc&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;https://blog.gnoack.org/images/perf-no_open.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;The decision which &lt;code&gt;f_op-&amp;gt;open&lt;/code&gt; is used for each file is done in &lt;code&gt;inode.c:init_special_inode&lt;/code&gt;, for sockets and pipes.&lt;/p&gt;&#xA;&lt;h2 id=&#34;summary&#34;&gt;Summary&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Every call to &lt;a href=&#34;https://man.gnoack.org/2/open&#34;&gt;&lt;em&gt;open&lt;/em&gt;(2)&lt;/a&gt; results in a new &lt;code&gt;struct file*&lt;/code&gt; being allocated.&lt;/li&gt;&#xA;&lt;li&gt;The resulting &lt;code&gt;struct file*&lt;/code&gt; refers to an existing inode, even for special files like pipes.&lt;/li&gt;&#xA;&lt;li&gt;Not all of the special files support this kind of re-opening.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;These &lt;code&gt;/dev/tcp/...&lt;/code&gt; files do not actually exist: bash treats these&#xA;paths specially and really just calls the BSD socket API&#xA;itself&amp;hellip; but we can use it here to write directly into a socket.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/proc-fd-is-not-dup/</guid>
      <pubDate>Mon, 19 Feb 2024 20:45:12 +0100</pubDate>
    </item>
    <item>
      <title>Go-Landlock: Networking support</title>
      <link>https://blog.gnoack.org/post/landlock-v4</link>
      <description>&lt;p&gt;In Linux 6.7, Konstantin Meskhidze introduced TCP Networking support&#xA;for Landlock. 🚀 I am happy to announce that Go-Landlock is one of the&#xA;first libraries using it, and it has a demo tool.&lt;/p&gt;&#xA;&lt;h2 id=&#34;demo&#34;&gt;Demo&lt;/h2&gt;&#xA;&lt;p&gt;If you are running Linux 6.7 or higher and have Landlock enabled, you can try it out like this:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Install the tool to &lt;code&gt;~/go/bin&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;go install github.com/landlock-lsm/go-landlock/cmd/landlock-restrict-net@latest&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Invoke the tool using:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;landlock-restrict-net -tcp.bind 8080 /usr/bin/nc -l 127.0.0.1 8080&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This invokes the command &lt;code&gt;nc -l 127.0.0.1 8080&lt;/code&gt; under a Landlock&#xA;policy where 8080 is the only TCP port which can be bound with&#xA;&lt;a href=&#34;https://man7.org/linux/man-pages/man2/bind.2.html&#34;&gt;&lt;em&gt;bind&lt;/em&gt;(2)&lt;/a&gt;.&#xA;The command listens on TCP port 8080, so this works.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;You can see the effect of the sandbox by changing one of the two port numbers:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;landlock-restrict-net -tcp.bind 8081 /usr/bin/nc -l 127.0.0.1 8080&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;In this case, the &lt;code&gt;nc&lt;/code&gt; command will fail to listen on 8080, because&#xA;this port can not be bound.  The sandbox works. 🎉&lt;/p&gt;&#xA;&lt;h2 id=&#34;go-api&#34;&gt;Go API&lt;/h2&gt;&#xA;&lt;p&gt;Landlock is not only useful to sandbox other programs from the&#xA;outside, but it shines when programs sandbox themselves.&lt;/p&gt;&#xA;&lt;p&gt;The Go API for Go-Landlock&amp;rsquo;s networking support is in line with the&#xA;API that Go-Landlock already provides for file system restrictions:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;err := landlock.V4.BestEffort().RestrictNet(&#xA;    landlock.BindTCP(8080),&#xA;    landlock.ConnectTCP(25),&#xA;    landlock.ConnectTCP(587),&#xA;)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This will enable a Landlock policy on the calling process, where:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;only TCP port 8080 can be bound with&#xA;&lt;a href=&#34;https://man7.org/linux/man-pages/man2/bind.2.html&#34;&gt;&lt;em&gt;bind&lt;/em&gt;(2)&lt;/a&gt;, and&lt;/li&gt;&#xA;&lt;li&gt;only TCP ports 25 and 587 can be connected to with&#xA;&lt;a href=&#34;https://man7.org/linux/man-pages/man2/connect.2.html&#34;&gt;&lt;em&gt;connect&lt;/em&gt;(2)&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The &lt;code&gt;RestrictNet()&lt;/code&gt; method is a new addition next to the previously&#xA;existing &lt;code&gt;RestrictPaths()&lt;/code&gt;.  These methods restrict &lt;em&gt;either&lt;/em&gt;&#xA;networking &lt;em&gt;or&lt;/em&gt; file system accesses.&lt;/p&gt;&#xA;&lt;p&gt;The other new addition is the &lt;a href=&#34;https://pkg.go.dev/github.com/landlock-lsm/go-landlock/landlock#hdr-Restricting_file_access_and_networking_at_once&#34;&gt;generic &lt;code&gt;Restrict()&lt;/code&gt;&#xA;method&lt;/a&gt;,&#xA;which restricts both networking and file system access at the same&#xA;time.&lt;/p&gt;&#xA;&lt;p&gt;Non-TCP protocols are currently unaffected by Landlock.  In&#xA;particular, UDP can still be freely used independent of any enabled&#xA;Landlock policies.&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/landlock-v4/</guid>
      <pubDate>Wed, 10 Jan 2024 21:23:00 +0100</pubDate>
    </item>
    <item>
      <title>Public tweets are not public, haha!</title>
      <link>https://blog.gnoack.org/post/social-media</link>
      <description>&lt;h2 id=&#34;twitter&#34;&gt;Twitter&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Posting: You can tweet, but the public can&amp;rsquo;t read it&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Reading: Most of my timeline is garbage.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;mastodon&#34;&gt;Mastodon&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Posting: Everything is quasi-public, and instance operators are all-knowing gods&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Reading: &lt;em&gt;All&lt;/em&gt; of my timeline is garbage.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I&amp;rsquo;m sad for Mastodon. It would have been an opportunity to reverse&#xA;the attention-grabbing engagement-through-outrage mechanisms,&#xA;which have already annoyed me on other social media platforms.&#xA;Somehow this did not work out.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-blogosphere&#34;&gt;The Blogosphere&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Posting: Everything is public, and it does not try to pretend otherwise.&lt;/li&gt;&#xA;&lt;li&gt;Reading: Readers control what they are reading through their RSS subscriptions.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;And this is the winner.&lt;/p&gt;&#xA;&lt;h2 id=&#34;summary&#34;&gt;Summary&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;I&amp;rsquo;m ditching Twitter.&lt;/li&gt;&#xA;&lt;li&gt;I&amp;rsquo;m not joining Mastodon.&lt;/li&gt;&#xA;&lt;li&gt;I keep operating this trusty weblog.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;If you don&amp;rsquo;t have one yet, &lt;em&gt;get yourself an RSS Reader app&lt;/em&gt;,&#xA;and &lt;em&gt;subscribe via RSS&lt;/em&gt;! (see link at the top)&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;Yes! Reading posts requires a Twitter account now!&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;Guarantees are difficult to make in a federated environment.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/social-media/</guid>
      <pubDate>Wed, 12 Jul 2023 20:38:02 +0200</pubDate>
    </item>
    <item>
      <title>The Design of Mailprint</title>
      <link>https://blog.gnoack.org/post/mailprint-design</link>
      <description>&lt;p&gt;I wrote a tool, &lt;a href=&#34;https://gnoack.github.io/mailprint/&#34;&gt;&lt;em&gt;Mailprint&lt;/em&gt;&lt;/a&gt;,&#xA;for printing out nice-looking emails from &lt;a href=&#34;http://www.mutt.org/&#34;&gt;Mutt&lt;/a&gt;&#xA;and other classic Mail user agents.&lt;/p&gt;&#xA;&lt;p&gt;(You might remember from the &lt;a href=&#34;https://blog.gnoack.org/post/lei/&#34;&gt;last article&lt;/a&gt;&#xA;that I have recently spent some time to polish my e-mail setup for kernel development.&#xA;While this is not the hip thing to do any more,&#xA;some of those mails are difficult to understand,&#xA;and I occasionally &lt;em&gt;print them out&lt;/em&gt;.)&lt;/p&gt;&#xA;&lt;p&gt;This article describes &lt;em&gt;Mailprint&lt;/em&gt;&amp;rsquo;s internals and design philosophy.&#xA;I&amp;rsquo;m fond of this approach, because it fits nicely into the UNIX environment and is reusable.&lt;/p&gt;&#xA;&lt;p&gt;If you are interested in &lt;em&gt;using&lt;/em&gt; &lt;em&gt;Mailprint&lt;/em&gt;, you can find its homepage at &lt;a href=&#34;https://gnoack.github.io/mailprint/&#34;&gt;https://gnoack.github.io/mailprint/&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;design-philosophy&#34;&gt;Design philosophy&lt;/h2&gt;&#xA;&lt;p&gt;Orthogonal software design, in the UNIX-style,&#xA;building one tool for each task, is great.&#xA;This applies in particular to side-projects,&#xA;because it is a way to achieve a lot more with less work.&lt;/p&gt;&#xA;&lt;p&gt;Mailprint is a tool which could have existed in similar form in the 80s already.&lt;/p&gt;&#xA;&lt;p&gt;It makes use of a pipeline of other tools to do its job:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;GNU troff (&lt;code&gt;groff&lt;/code&gt;) to format pages&lt;/li&gt;&#xA;&lt;li&gt;ImageMagick&amp;rsquo;s &lt;code&gt;convert&lt;/code&gt; to convert profile pictures from various image formats&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;interface-to-the-outside&#34;&gt;Interface to the outside&lt;/h3&gt;&#xA;&lt;p&gt;&lt;strong&gt;To the outside,&lt;/strong&gt;&#xA;Mailprint is designed to be used as part of a UNIX pipeline,&#xA;reading a plain text email and outputting PDF:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;cat ~/.Mail/Inbox/cur/foobar123 | mailprint &amp;gt; out.pdf&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;div id=&#39;pikchr-0&#39; class=&#39;pikchr&#39;&gt;&#xA;&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:260px&#39;&gt;&#xA;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 260.64 76.32&#34;&gt;&#xA;&lt;polygon points=&#34;74.16,38.16 62.64,42.48 62.64,33.84&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M2.16,38.16L68.4,38.16&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;38.16&#34; y=&#34;26.46&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;email&lt;/text&gt;&#xA;&lt;path d=&#34;M74.16,74.16L182.16,74.16L182.16,2.16L74.16,2.16Z&#34;  style=&#34;fill:rgb(255,255,224);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;128.16&#34; y=&#34;38.16&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;mailprint&lt;/text&gt;&#xA;&lt;polygon points=&#34;254.16,38.16 242.64,42.48 242.64,33.84&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M182.16,38.16L248.4,38.16&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;218.16&#34; y=&#34;26.46&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;PDF&lt;/text&gt;&#xA;&lt;/svg&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;This makes it easy to hook up Mailprint to &lt;code&gt;mutt&lt;/code&gt; and other classic MUAs.&lt;/p&gt;&#xA;&lt;h3 id=&#34;internal-design&#34;&gt;Internal design&lt;/h3&gt;&#xA;&lt;blockquote class=&#34;warning&#34;&gt;&lt;p&gt;⚠️ &lt;strong&gt;This section is not up-to-date any more.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;More recent versions of Mailprint generate PDF directly with a PDF generation library&#xA;and do not start additional child processes.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Internally, Mailprint generates &lt;a href=&#34;http://www.schaffter.ca/mom/momdoc/toc.html&#34;&gt;groff source code in the &amp;ldquo;mom&amp;rdquo; dialect&lt;/a&gt; from the input email and feeds it through a UNIX pipeline of processing tools:&lt;/p&gt;&#xA;&lt;div id=&#39;pikchr-1&#39; class=&#39;pikchr&#39;&gt;&#xA;&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:980px&#39;&gt;&#xA;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 980.64 236.336&#34;&gt;&#xA;&lt;path d=&#34;M93.1521,234.176L883.168,234.176L883.168,2.16L93.1521,2.16Z&#34;  style=&#34;fill:rgb(255,255,224);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;polygon points=&#34;110.16,181.168 98.64,185.488 98.64,176.848&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M2.16,181.168L104.4,181.168&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;169.468&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;email&lt;/text&gt;&#xA;&lt;path d=&#34;M110.16,217.168L218.16,217.168L218.16,145.168L110.16,145.168Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;164.16&#34; y=&#34;181.168&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;parse email&lt;/text&gt;&#xA;&lt;polygon points=&#34;326.16,181.168 314.64,185.488 314.64,176.848&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M218.16,181.168L320.4,181.168&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;272.16&#34; y=&#34;169.468&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;headers,&lt;/text&gt;&#xA;&lt;text x=&#34;272.16&#34; y=&#34;192.868&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;body&lt;/text&gt;&#xA;&lt;path d=&#34;M326.16,217.168L434.16,217.168L434.16,145.168L326.16,145.168Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;380.16&#34; y=&#34;161.008&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;convert&lt;/text&gt;&#xA;&lt;text x=&#34;380.16&#34; y=&#34;181.168&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;email&lt;/text&gt;&#xA;&lt;text x=&#34;380.16&#34; y=&#34;201.328&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;to groff&lt;/text&gt;&#xA;&lt;polygon points=&#34;542.16,181.168 530.64,185.488 530.64,176.848&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M434.16,181.168L536.4,181.168&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;488.16&#34; y=&#34;169.468&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;mom&lt;/text&gt;&#xA;&lt;text x=&#34;488.16&#34; y=&#34;192.868&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;(groff&lt;/text&gt;&#xA;&lt;text x=&#34;488.16&#34; y=&#34;213.028&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;source)&lt;/text&gt;&#xA;&lt;path d=&#34;M542.16,217.168L650.16,217.168L650.16,145.168L542.16,145.168Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;596.16&#34; y=&#34;181.168&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;preconv&lt;/text&gt;&#xA;&lt;polygon points=&#34;758.16,181.168 746.64,185.488 746.64,176.848&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M650.16,181.168L752.4,181.168&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;704.16&#34; y=&#34;169.468&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;mom&lt;/text&gt;&#xA;&lt;text x=&#34;704.16&#34; y=&#34;192.868&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;(sanitized&lt;/text&gt;&#xA;&lt;text x=&#34;704.16&#34; y=&#34;213.028&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;Unicode)&lt;/text&gt;&#xA;&lt;path d=&#34;M758.16,217.168L866.16,217.168L866.16,145.168L758.16,145.168Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;812.16&#34; y=&#34;171.088&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;groff&lt;/text&gt;&#xA;&lt;text x=&#34;812.16&#34; y=&#34;191.248&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;-mom -Tpdf&lt;/text&gt;&#xA;&lt;polygon points=&#34;974.16,181.168 962.64,185.488 962.64,176.848&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M866.16,181.168L968.4,181.168&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;920.16&#34; y=&#34;169.468&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;PDF&lt;/text&gt;&#xA;&lt;path d=&#34;M164.16,145.168L164.16,73.1679&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;164.16&#34; y=&#34;97.4679&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; transform=&#34;rotate(-90 164.16,109.168)&#34; dominant-baseline=&#34;central&#34;&gt;sender&lt;/text&gt;&#xA;&lt;text x=&#34;164.16&#34; y=&#34;120.868&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; transform=&#34;rotate(-90 164.16,109.168)&#34; dominant-baseline=&#34;central&#34;&gt;address&lt;/text&gt;&#xA;&lt;polygon points=&#34;218.16,73.1679 206.64,77.4879 206.64,68.8479&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M164.16,73.1679L212.4,73.1679&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M218.16,109.168L326.16,109.168L326.16,37.1679L218.16,37.1679Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;272.16&#34; y=&#34;63.0879&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;look up&lt;/text&gt;&#xA;&lt;text x=&#34;272.16&#34; y=&#34;83.2479&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;face&lt;/text&gt;&#xA;&lt;polygon points=&#34;434.16,73.1679 422.64,77.4879 422.64,68.8479&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M326.16,73.1679L428.4,73.1679&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;380.16&#34; y=&#34;61.4679&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;filename&lt;/text&gt;&#xA;&lt;path d=&#34;M434.16,109.168L542.16,109.168L542.16,37.1679L434.16,37.1679Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;488.16&#34; y=&#34;63.0879&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;ImageMagick&lt;/text&gt;&#xA;&lt;text x=&#34;488.16&#34; y=&#34;83.2479&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;convert&lt;/text&gt;&#xA;&lt;polygon points=&#34;650.16,73.1679 638.64,77.4879 638.64,68.8479&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M542.16,73.1679L644.4,73.1679&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M650.16,127.168L722.16,127.168L722.16,40.7679L700.56,19.1679L650.16,19.1679Z&#34;  style=&#34;fill:rgb(255,255,255);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M700.56,19.1679L700.56,40.7679L722.16,40.7679&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;686.16&#34; y=&#34;63.0879&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;PDF&lt;/text&gt;&#xA;&lt;text x=&#34;686.16&#34; y=&#34;83.2479&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;file&lt;/text&gt;&#xA;&lt;polygon points=&#34;812.16,145.168 807.84,133.648 816.48,133.648&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M722.16,73.1679L812.16,73.1679L812.16,139.408&#34;  style=&#34;fill:none;stroke-width:2.16;stroke-linejoin:round;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;874.664&#34; y=&#34;12.24&#34; text-anchor=&#34;end&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;mailprint&lt;/text&gt;&#xA;&lt;/svg&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;The steps implemented in Go are:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Parsing emails&lt;/strong&gt; into email headers and bodies. (&lt;a href=&#34;https://github.com/gnoack/mailprint/blob/main/parse.go&#34;&gt;code&lt;/a&gt;)&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Looking up the sender&amp;rsquo;s profile picture:&lt;/strong&gt;&#xA;This is also a separate Go library, &lt;a href=&#34;https://github.com/gnoack/picon&#34;&gt;picon&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Converting the email to groff source code&lt;/strong&gt;&#xA;&lt;a href=&#34;http://www.schaffter.ca/mom/momdoc/toc.html&#34;&gt;of the &amp;ldquo;mom&amp;rdquo; flavor&lt;/a&gt;,&#xA;which is the heart of the program. (&lt;a href=&#34;https://github.com/gnoack/mailprint/blob/main/render.go&#34;&gt;code&lt;/a&gt;)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The remaining steps are accomplished by invoking external UNIX programs:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;ImageMagick &lt;code&gt;convert&lt;/code&gt;&lt;/strong&gt; converts the discovered profile pictures from various source formats into the PDF format.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;preconv&lt;/code&gt;&lt;/strong&gt; belongs to the groff suite and converts Unicode characters into input that GNU troff understands.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;groff&lt;/code&gt;&lt;/strong&gt; finally creates the PDF from the input source.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The pipeline is invoked from Mailprint&amp;rsquo;s top-level &lt;code&gt;run()&lt;/code&gt; function. (&lt;a href=&#34;https://github.com/gnoack/mailprint/blob/main/cmd/mailprint/main.go#L127&#34;&gt;code&lt;/a&gt;)&lt;/p&gt;&#xA;&lt;h3 id=&#34;turning-it-inside-out&#34;&gt;Turning it inside-out&lt;/h3&gt;&#xA;&lt;p&gt;If you want to build a more custom Mailprint pipeline, you can also make Mailprint expose its groff intermediary format using the &lt;code&gt;-output.format=mom&lt;/code&gt; option, and chain it with groff yourself:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;mailprint -face.picon=false -output.format=mom | preconv | groff -mom -Tpdf | lpr&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;div id=&#39;pikchr-2&#39; class=&#39;pikchr&#39;&gt;&#xA;&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:980px&#39;&gt;&#xA;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 980.64 127.344&#34;&gt;&#xA;&lt;path d=&#34;M93.1521,125.184L451.168,125.184L451.168,2.16L93.1521,2.16Z&#34;  style=&#34;fill:rgb(255,255,224);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;polygon points=&#34;110.16,72.1757 98.64,76.4957 98.64,67.8557&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M2.16,72.1757L104.4,72.1757&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;56.16&#34; y=&#34;60.4757&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;email&lt;/text&gt;&#xA;&lt;path d=&#34;M110.16,108.176L218.16,108.176L218.16,36.1757L110.16,36.1757Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;164.16&#34; y=&#34;72.1757&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;parse email&lt;/text&gt;&#xA;&lt;polygon points=&#34;326.16,72.1757 314.64,76.4957 314.64,67.8557&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M218.16,72.1757L320.4,72.1757&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;272.16&#34; y=&#34;60.4757&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;headers,&lt;/text&gt;&#xA;&lt;text x=&#34;272.16&#34; y=&#34;83.8757&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;body&lt;/text&gt;&#xA;&lt;path d=&#34;M326.16,108.176L434.16,108.176L434.16,36.1757L326.16,36.1757Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;380.16&#34; y=&#34;52.0157&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;convert&lt;/text&gt;&#xA;&lt;text x=&#34;380.16&#34; y=&#34;72.1757&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;email&lt;/text&gt;&#xA;&lt;text x=&#34;380.16&#34; y=&#34;92.3357&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;to groff&lt;/text&gt;&#xA;&lt;polygon points=&#34;542.16,72.1757 530.64,76.4957 530.64,67.8557&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M434.16,72.1757L536.4,72.1757&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;488.16&#34; y=&#34;60.4757&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;mom&lt;/text&gt;&#xA;&lt;text x=&#34;488.16&#34; y=&#34;83.8757&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;(groff&lt;/text&gt;&#xA;&lt;text x=&#34;488.16&#34; y=&#34;104.036&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;source)&lt;/text&gt;&#xA;&lt;path d=&#34;M542.16,108.176L650.16,108.176L650.16,36.1757L542.16,36.1757Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;596.16&#34; y=&#34;72.1757&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;preconv&lt;/text&gt;&#xA;&lt;polygon points=&#34;758.16,72.1757 746.64,76.4957 746.64,67.8557&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M650.16,72.1757L752.4,72.1757&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;704.16&#34; y=&#34;60.4757&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;mom&lt;/text&gt;&#xA;&lt;text x=&#34;704.16&#34; y=&#34;83.8757&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;(sanitized&lt;/text&gt;&#xA;&lt;text x=&#34;704.16&#34; y=&#34;104.036&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;Unicode)&lt;/text&gt;&#xA;&lt;path d=&#34;M758.16,108.176L866.16,108.176L866.16,36.1757L758.16,36.1757Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;812.16&#34; y=&#34;62.0957&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;groff&lt;/text&gt;&#xA;&lt;text x=&#34;812.16&#34; y=&#34;82.2557&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;-mom -Tpdf&lt;/text&gt;&#xA;&lt;polygon points=&#34;974.16,72.1757 962.64,76.4957 962.64,67.8557&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M866.16,72.1757L968.4,72.1757&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;920.16&#34; y=&#34;60.4757&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;PDF&lt;/text&gt;&#xA;&lt;text x=&#34;442.664&#34; y=&#34;12.24&#34; text-anchor=&#34;end&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;mailprint -output.format=mom -face.picon=false&lt;/text&gt;&#xA;&lt;/svg&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/mailprint-design/</guid>
      <pubDate>Thu, 22 Jun 2023 22:04:56 +0200</pubDate>
    </item>
    <item>
      <title>Lei, the Local Email Interface</title>
      <link>https://blog.gnoack.org/post/lei</link>
      <description>&lt;h2 id=&#34;intro&#34;&gt;Intro&lt;/h2&gt;&#xA;&lt;p&gt;When I came back to the email account where I first subscribed to LKML,&#xA;it was &lt;em&gt;full&lt;/em&gt;.&lt;/p&gt;&#xA;&lt;p&gt;But if you are anyway using a local email client like &lt;code&gt;mutt&lt;/code&gt;,&#xA;there is a better option than subscribing via email:&#xA;The &lt;code&gt;lei&lt;/code&gt; program lets you import Linux mailing list archives into local maildirs:&lt;/p&gt;&#xA;&lt;div id=&#39;pikchr-0&#39; class=&#39;pikchr&#39;&gt;&#xA;&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:486px&#39;&gt;&#xA;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 486.72 165.413&#34;&gt;&#xA;&lt;path d=&#34;M2.16,156.053L131.76,156.053L131.76,84.0529L2.16,84.0529Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;66.96&#34; y=&#34;109.973&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;public-inbox at&lt;/text&gt;&#xA;&lt;text x=&#34;66.96&#34; y=&#34;130.133&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;lore.kernel.org&lt;/text&gt;&#xA;&lt;polygon points=&#34;131.76,120.053 143.28,115.733 143.28,124.373&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M137.52,120.053L203.76,120.053&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;167.76&#34; y=&#34;108.353&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;2. query&lt;/text&gt;&#xA;&lt;path d=&#34;M203.76,156.053L311.76,156.053L311.76,84.0529L203.76,84.0529Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;257.76&#34; y=&#34;120.053&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;lei&lt;/text&gt;&#xA;&lt;polygon points=&#34;398.16,120.053 386.64,124.373 386.64,115.733&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M311.76,120.053L392.4,120.053&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;354.96&#34; y=&#34;108.353&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;3. store&lt;/text&gt;&#xA;&lt;path d=&#34;M398.16,87.6529L398.16,152.453A43.2 10.8 0 0 0 484.56 152.453L484.56,87.6529A43.2 10.8 0 0 0 398.16 87.6529A43.2 10.8 0 0 0 484.56 87.6529&#34;  style=&#34;fill:rgb(255,255,224);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;441.36&#34; y=&#34;118.073&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;local&lt;/text&gt;&#xA;&lt;text x=&#34;441.36&#34; y=&#34;138.233&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;maildir&lt;/text&gt;&#xA;&lt;polygon points=&#34;257.76,84.0529 253.44,72.5329 262.08,72.5329&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M257.76,78.2929L257.76,27.36&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;257.76&#34; y=&#34;55.7065&#34; text-anchor=&#34;start&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt; 1. lei up --all&lt;/text&gt;&#xA;&lt;text x=&#34;257.76&#34; y=&#34;12.24&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;user&lt;/text&gt;&#xA;&lt;/svg&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;The server side needs to run the &lt;a href=&#34;https://public-inbox.org&#34;&gt;public-inbox&lt;/a&gt; software.&lt;/p&gt;&#xA;&lt;h2 id=&#34;set-up&#34;&gt;Set up&lt;/h2&gt;&#xA;&lt;p&gt;First, create a directory for your maildirs:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;mkdir -p .Mail/lei&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;Arch Linux installs &lt;code&gt;lei&lt;/code&gt; into an unusual location.  In this case, add this to &lt;code&gt;.bashrc&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;alias lei=/usr/bin/vendor_perl/lei&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h2 id=&#34;subscriptionsearch-management&#34;&gt;Subscription/Search management&lt;/h2&gt;&#xA;&lt;p&gt;Subscribe to various mailing lists and to the mails that go to yourself (&lt;a href=&#34;https://lore.kernel.org/all/_/text/help/&#34;&gt;Query Language&lt;/a&gt;):&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;# Linux Security Module list&#xA;lei q --only=https://lore.kernel.org/linux-security-module \&#xA;      --output=&amp;quot;${HOME}/.Mail/lei/lsm&amp;quot;                     \&#xA;      &#39;rt:12.months.ago..&#39;&#xA;&#xA;# Linux Man Pages list&#xA;lei q --only=https://lore.kernel.org/linux-man \&#xA;      --output=&amp;quot;${HOME}/.Mail/lei/man&amp;quot;         \&#xA;      &#39;rt:12.months.ago..&#39;&#xA;&#xA;# Mails where I am in To: or Cc:, and the surrounding threads&#xA;lei q --only=https://lore.kernel.org/all \&#xA;      --output=&amp;quot;${HOME}/.Mail/lei/tome&amp;quot;  \&#xA;      --threads                          \&#xA;      &#39;a:myemail@example.com rt:36.months.ago..&#39;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The &lt;code&gt;lei q&lt;/code&gt; command is not issuing a single-shot query,&#xA;but it is storing the query locally as a subscription.&lt;/p&gt;&#xA;&lt;p&gt;These subscriptions are called &amp;ldquo;searches&amp;rdquo; in lei lingo,&#xA;and their results are stored in the given maildir directories.&lt;/p&gt;&#xA;&lt;p&gt;To see all the searches you have, use:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;lei ls-search&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;To remove an existing search, use&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;lei forget-search &amp;quot;${HOME}/.Mail/lei/lsm&amp;quot;  # example&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2 id=&#34;regularly-update-subscriptionssearches&#34;&gt;Regularly: Update subscriptions/searches&lt;/h2&gt;&#xA;&lt;p&gt;To update all lei subscriptions and populate new content into the maildirs:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;lei up --all&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Now you are all set, and you can read the mailing lists with the MUA of your choice:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;mutt -f ~/.Mail/lei/lsm&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2 id=&#34;references&#34;&gt;References&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://people.kernel.org/monsieuricon/lore-lei-part-1-getting-started&#34;&gt;lore+lei: part 1, getting started&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://people.kernel.org/monsieuricon/lore-lei-part-2-now-with-imap&#34;&gt;lore+lei, part 2, now with IMAP&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://lwn.net/Articles/878205/&#34;&gt;LWN: Digging into the community&amp;rsquo;s lore with lei&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Thanks to &lt;a href=&#34;http://derkling.matbug.net/blog:email_setup&#34;&gt;derkling&lt;/a&gt;, who pointed me to &lt;code&gt;lei&lt;/code&gt;!&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/lei/</guid>
      <pubDate>Sun, 11 Jun 2023 20:13:00 +0200</pubDate>
    </item>
    <item>
      <title>The empty Makefile is valid</title>
      <link>https://blog.gnoack.org/post/empty-makefiles</link>
      <description>&lt;p&gt;This is less of a &amp;ldquo;Today I learned&amp;rdquo; article, but more like a Unix&#xA;trick that took me too long to realize.&lt;/p&gt;&#xA;&lt;p&gt;Create a new directory with a hello world C program:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;$ ls&#xA;$ cat &amp;gt; hello.c&#xA;#include &amp;lt;stdio.h&amp;gt;&#xA;&#xA;int main() {&#xA;  puts(&amp;quot;Hello, world!&amp;quot;);&#xA;  return 0;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;💡 The empty or non-existent Makefile is a valid makefile for this C&#xA;program:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;$ make hello                # build &amp;quot;hello&amp;quot;&#xA;cc     hello.c   -o hello&#xA;$ ./hello&#xA;Hello, world!&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/empty-makefiles/</guid>
      <pubDate>Wed, 10 May 2023 19:00:00 +0200</pubDate>
    </item>
    <item>
      <title>Landlock: Best Effort mode</title>
      <link>https://blog.gnoack.org/post/landlock-best-effort</link>
      <description>&lt;ul id=&#34;toc&#34;&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#abi-versions-and-matching-access-rights&#34;&gt;ABI versions and matching access rights&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#the-problem-refer-is-different&#34;&gt;The problem: Refer is different&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#implementation-of-best-effort-fallback-in-c&#34;&gt;Implementation of best-effort fallback in C&lt;/a&gt;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#common-part-abi-version-compatibility-table&#34;&gt;Common part: ABI version compatibility table&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#case-1-the-sandboxed-program-does-not-need-to-reparent-files&#34;&gt;Case 1: the sandboxed program does not need to reparent files&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#case-2-the-sandboxed-program-needs-to-reparent-files&#34;&gt;Case 2: the sandboxed program needs to reparent files&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#case-3-sometimes-this-sometimes-that&#34;&gt;Case 3: Sometimes this, sometimes that&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#conclusion&#34;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#references&#34;&gt;References&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;One of Landlock&amp;rsquo;s strengths is that you can deploy the same program on&#xA;multiple kernel versions, and make it use the best available&#xA;sandboxing on each.&lt;/p&gt;&#xA;&lt;p&gt;This &amp;ldquo;best effort&amp;rdquo; approach is already implemented for you &lt;a href=&#34;https://pkg.go.dev/github.com/landlock-lsm/go-landlock/landlock#Config.BestEffort&#34;&gt;in the&#xA;Go-Landlock&#xA;library&lt;/a&gt;&#xA;and &lt;a href=&#34;https://landlock.io/rust-landlock/landlock/#compatibility&#34;&gt;in the Rust Landlock&#xA;library&lt;/a&gt;.&#xA;But what if you need to implement it yourself?&lt;/p&gt;&#xA;&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&#xA;This article assumes previous knowledge of Landlock - you can read more about the abstract model in the &lt;a href=&#34;https://docs.google.com/document/d/1SkFpl_Xxyl4E6G2uYIlzL0gY2PFo-Nl8ikblLvnpvlU/edit#&#34;&gt;Landlock File System Access Model&lt;/a&gt; document which I&amp;rsquo;ve written previously, or in the &lt;a href=&#34;https://docs.kernel.org/userspace-api/landlock.html&#34;&gt;official Landlock documentation&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h2 id=&#34;abi-versions-and-matching-access-rights&#34;&gt;ABI versions and matching access rights&lt;/h2&gt;&#xA;&lt;!-- TODO: Link the man page here when it&#39;s part of the man page --&gt;&#xA;&lt;p&gt;Landlock exposes its feature set in the form of a numeric Landlock ABI&#xA;version.&lt;/p&gt;&#xA;&lt;p&gt;In order to implement the fallback correctly, you need to know which&#xA;file system access rights are supported in which ABI version.&lt;/p&gt;&#xA;&lt;p&gt;The (simplified) compatibility chart as of Linux 6.2 is:&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;ABI&lt;/th&gt;&#xA;&lt;th&gt;Linux&lt;/th&gt;&#xA;&lt;th&gt;File system access rights&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;1&lt;/td&gt;&#xA;&lt;td&gt;5.13&lt;/td&gt;&#xA;&lt;td&gt;almost all of the basic file operations (compare &lt;a href=&#34;https://docs.kernel.org/userspace-api/landlock.html#filesystem-flags&#34;&gt;kernel docs&lt;/a&gt;)&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;2&lt;/td&gt;&#xA;&lt;td&gt;5.19&lt;/td&gt;&#xA;&lt;td&gt;+&lt;code&gt;LANDLOCK_ACCESS_FS_REFER&lt;/code&gt; (reparenting files)&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;3&lt;/td&gt;&#xA;&lt;td&gt;6.2&lt;/td&gt;&#xA;&lt;td&gt;+&lt;code&gt;LANDLOCK_ACCESS_FS_TRUNCATE&lt;/code&gt; (truncating files)&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;Further below, we will define this support matrix in C.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-problem-refer-is-different&#34;&gt;The problem: Refer is different&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;The backwards compatibility works differently for &amp;ldquo;refer&amp;rdquo; than for&#xA;other access rights&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;Skip this section if you are only interested in the C code.&lt;/div&gt;&#xA;&lt;p&gt;Each Landlock ABI version is characterized by three disjoint sets of&#xA;file system operations: The &lt;em&gt;Always Forbidden&lt;/em&gt; operations, the&#xA;&lt;em&gt;Configurable&lt;/em&gt; operations and the &lt;em&gt;Always Permitted&lt;/em&gt; operations.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;em&gt;Configurable&lt;/em&gt; operations are the ones which already have names in&#xA;the &lt;code&gt;landlock.h&lt;/code&gt; header.  With increasing ABI versions, all relevant&#xA;operations should become &amp;ldquo;Configurable&amp;rdquo;, in particular the &amp;ldquo;Always&#xA;permitted&amp;rdquo; operations.&lt;/p&gt;&#xA;&lt;p&gt;In ABI v1, an set of useful file system operations is configurable in&#xA;Landlock, but there is also a longer list of known operations which is&#xA;always permitted (Landlock can not restrict them). Finally, some more&#xA;complicated interactions are always forbidden because they would&#xA;interfere with Landlock&amp;rsquo;s guarantees:&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/images/ll-permissions.svg&#34; alt=&#34;&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;When introducing ABI v2, the &amp;ldquo;refer&amp;rdquo; operation, which was previously&#xA;forbidden, became configurable:&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/images/ll-permissions-v2.svg&#34; alt=&#34;&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;With ABI v2, it is now possible to reparent (link(2) or rename(2))&#xA;files between different directories, as long as the involved files and&#xA;directories meet certain constraints about their access rights.&lt;/p&gt;&#xA;&lt;p&gt;The behavior of &amp;ldquo;refer&amp;rdquo; is different to &amp;ldquo;truncate&amp;rdquo; and other future access rights, which fall back to &lt;em&gt;Always Permitted&lt;/em&gt; in earlier ABI versions, and so &amp;ldquo;refer&amp;rdquo; needs a different fallback logic.&lt;/p&gt;&#xA;&lt;blockquote class=&#34;rule&#34;&gt;&lt;p&gt;If a program needs to do a &amp;ldquo;refer&amp;rdquo; (reparent files between directories),&#xA;using ABI v1 is not an option.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;!-- todo: mention man page --&gt;&#xA;&lt;p&gt;The canonical documentation for this interaction is the &lt;a href=&#34;https://docs.kernel.org/userspace-api/landlock.html#filesystem-flags&#34;&gt;kernel&#xA;documentation&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;implementation-of-best-effort-fallback-in-c&#34;&gt;Implementation of best-effort fallback in C&lt;/h2&gt;&#xA;&lt;p&gt;To implement the fallback logic, we will (a) define the compatibility&#xA;table, and then, (b) depending on whether your program needs to do&#xA;file reparenting, implement a slightly different fallback logic based&#xA;on that compatibility table.&lt;/p&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;This question decides which approach to use.&lt;/div&gt;&#xA;&lt;p&gt;The question to ask is:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Does your program need to do any file reparenting (&amp;ldquo;refer&amp;rdquo;)?&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;File reparenting means: Creating hard links or moving files or&#xA;directories, between &lt;em&gt;different&lt;/em&gt;(!) directories (compare &lt;a href=&#34;https://docs.kernel.org/userspace-api/landlock.html#filesystem-flags&#34;&gt;the kernel&#xA;documentation&lt;/a&gt;).&lt;/p&gt;&#xA;&lt;h3 id=&#34;common-part-abi-version-compatibility-table&#34;&gt;Common part: ABI version compatibility table&lt;/h3&gt;&#xA;&lt;p&gt;We define a small C array to hold the file system access rights which&#xA;are supported by the different Landlock ABI versions.  We store one&#xA;&lt;code&gt;__u64&lt;/code&gt; bitmask for each ABI version.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;__u64 landlock_fs_access_rights[] = {&#xA;  (1ULL &amp;lt;&amp;lt; 13) - 1,  /* ABI v1                 */&#xA;  (1ULL &amp;lt;&amp;lt; 14) - 1,  /* ABI v2: add &amp;quot;refer&amp;quot;    */&#xA;  (1ULL &amp;lt;&amp;lt; 15) - 1,  /* ABI v3: add &amp;quot;truncate&amp;quot; */&#xA;};&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;I&amp;rsquo;m keeping it short here for brevity, but you can also use the constants from &lt;a href=&#34;https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/landlock.h?h=v6.2&#34;&gt;linux/landlock.h&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;case-1-the-sandboxed-program-does-not-need-to-reparent-files&#34;&gt;Case 1: the sandboxed program does &lt;em&gt;not&lt;/em&gt; need to reparent files&lt;/h3&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;Use this approach, if you don&#39;t use link(2) and rename(2) across directory boundaries.&lt;/div&gt;&#xA;&lt;p&gt;If the sandboxed program does &lt;em&gt;not&lt;/em&gt; need to reparent files, the&#xA;best-effort logic is to simply remove the unsupported rights from &lt;code&gt;ruleset_attr.handled_access_fs&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;This code needs to be inserted &lt;em&gt;after&lt;/em&gt; you have filled a &lt;code&gt;struct landlock_ruleset_attr&lt;/code&gt; variable, but before you create the ruleset&#xA;from it:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;int abi = landlock_create_ruleset(NULL, 0,&#xA;                                  LANDLOCK_CREATE_RULESET_VERSION);&#xA;if (abi &amp;lt;= 0) {&#xA;  /*&#xA;   * This kernel does not let us use Landlock.&#xA;   * Best effort: Give up, and do not restrict the process.&#xA;   */&#xA;  return 0;&#xA;}&#xA;if (abi &amp;gt; ARRAY_SIZE(landlock_fs_access_rights)) {&#xA;  /* Kernel from the future: Treat as highest known ABI version. */&#xA;  abi = ARRAY_SIZE(landlock_fs_access_rights);&#xA;}&#xA;ruleset_attr.handled_access_fs &amp;amp;= landlock_fs_access_rights[abi-1];&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;Don&#39;t forget this!&lt;/div&gt;&#xA;&lt;p&gt;Additionally, before you add a &amp;ldquo;path beneath&amp;rdquo; Landlock rule to the&#xA;ruleset, make sure that the requested access rights fit into the&#xA;previously restricted &lt;code&gt;handled_access_fs&lt;/code&gt; rights:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;path_beneath.allowed_access &amp;amp;= ruleset_attr.handled_access_fs;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h3 id=&#34;case-2-the-sandboxed-program-needs-to-reparent-files&#34;&gt;Case 2: the sandboxed program needs to reparent files&lt;/h3&gt;&#xA;&lt;p&gt;If the sandboxed program &lt;em&gt;does&lt;/em&gt; need to reparent files, the&#xA;best-effort logic works the same as above, &lt;em&gt;but it has a special case&#xA;for ABI version 1&lt;/em&gt;.  In this ABI version, file reparenting does not&#xA;work under Landlock at all, and so we have to give up on it.&lt;/p&gt;&#xA;&lt;p&gt;This code needs to be inserted &lt;em&gt;after&lt;/em&gt; you have filled a &lt;code&gt;struct landlock_ruleset_attr&lt;/code&gt; variable, but before you create the ruleset&#xA;from it:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;int abi = landlock_create_ruleset(NULL, 0,&#xA;                                  LANDLOCK_CREATE_RULESET_VERSION);&#xA;switch (abi) {&#xA;  case -1:&#xA;  case 0:  /* should not happen */&#xA;    /*&#xA;     * This kernel does not let us use Landlock.&#xA;     * Best effort: Give up, and do not restrict the process.&#xA;     */&#xA;    return 0;&#xA;  case 1:&#xA;    /*&#xA;     * This kernel only supports Landlock ABI v1.&#xA;     * We need the &amp;quot;refer&amp;quot; right, but it&#39;s not supported in ABI v1.&#xA;     * Best effort: Give up, and do not restrict the process.&#xA;     */&#xA;    return 0;&#xA;  default:&#xA;    if (abi &amp;gt; ARRAY_SIZE(landlock_fs_access_rights)) {&#xA;      /* &#xA;       * A kernel with Landlock suppport from the future!&#xA;       * Treat it as the highest known ABI version.&#xA;       */&#xA;      abi = ARRAY_SIZE(landlock_fs_access_rights);&#xA;    }&#xA;    ruleset_attr.handled_access_fs &amp;amp;= landlock_fs_access_rights[abi-1];&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Additionally, before you add a &amp;ldquo;path beneath&amp;rdquo; Landlock rule to the&#xA;ruleset, make sure that the requested access rights fit into the&#xA;previously restricted &lt;code&gt;handled_access_fs&lt;/code&gt; rights:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;path_beneath.allowed_access &amp;amp;= ruleset_attr.handled_access_fs;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h3 id=&#34;case-3-sometimes-this-sometimes-that&#34;&gt;Case 3: Sometimes this, sometimes that&lt;/h3&gt;&#xA;&lt;p&gt;This is the complicated case which we also implemented in the Go and&#xA;Rust Landlock libraries.  These libraries figure out at runtime which&#xA;of the two cases we are in, and then use the adequate approach as&#xA;above.&lt;/p&gt;&#xA;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;&#xA;&lt;p&gt;In the long run, when Landlock has stabilized more, and as older&#xA;kernels become less relevant, this complication will hopefully go&#xA;away.  Until then, I&amp;rsquo;m hopeful that most users can simply use the&#xA;simple approach in Case 1 above, because their programs do not need&#xA;the &amp;ldquo;refer&amp;rdquo; right.&lt;/p&gt;&#xA;&lt;h2 id=&#34;references&#34;&gt;References&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;I&amp;rsquo;ve previously written about this more in the abstract at: &lt;a href=&#34;https://docs.google.com/document/d/1SkFpl_Xxyl4E6G2uYIlzL0gY2PFo-Nl8ikblLvnpvlU/edit#&#34;&gt;Landlock File System Access&#xA;Model&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://landlock.io/&#34;&gt;https://landlock.io/&lt;/a&gt; - Official Landlock page&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://docs.kernel.org/userspace-api/landlock.html&#34;&gt;Landlock kernel documentation&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Thank you Mickaël, for pointing out some issues in this article!&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/landlock-best-effort/</guid>
      <pubDate>Sun, 05 Mar 2023 10:34:09 +0100</pubDate>
    </item>
    <item>
      <title>Landlock truncation support in Linux 6.2</title>
      <link>https://blog.gnoack.org/post/landlock-truncate</link>
      <description>&lt;p&gt;Linus Torvalds released Linux 6.2 yesterday, and this kernel release&#xA;supports restricting the &lt;code&gt;truncate(2)&lt;/code&gt; and &lt;code&gt;ftruncate(2)&lt;/code&gt; operations&#xA;with Landlock. (The &lt;a href=&#34;https://lore.kernel.org/all/20221018182216.301684-1-gnoack3000@gmail.com/&#34;&gt;kernel patch&#xA;set&lt;/a&gt;&#xA;has more information and discussion.)&lt;/p&gt;&#xA;&lt;p&gt;You can try this out today with the&#xA;&lt;a href=&#34;https://github.com/landlock-lsm/go-landlock&#34;&gt;go-landlock&lt;/a&gt; library,&#xA;which already supports this feature. To forbid file truncation when&#xA;using &lt;code&gt;go-landlock&lt;/code&gt;, update your &lt;code&gt;RestrictPaths()&lt;/code&gt; invocation to use&#xA;Landlock version 3 as follows:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;err := landlock.V3.BestEffort().RestrictPaths(&#xA;    landlock.RODirs(&amp;quot;/usr&amp;quot;, &amp;quot;/bin&amp;quot;),&#xA;    landlock.RWDirs(&amp;quot;/tmp&amp;quot;),&#xA;)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Most existing users will only need to exchange &lt;code&gt;V2&lt;/code&gt; for &lt;code&gt;V3&lt;/code&gt;. When&#xA;using &lt;code&gt;landlock.V3&lt;/code&gt; this way, file truncation is forbidden by default.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;RWFiles()&lt;/code&gt; and &lt;code&gt;RWDirs()&lt;/code&gt; helpers grant the truncation right when&#xA;used on a file or directory. (It comes hand in hand with the right to&#xA;open files for writing.)&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/landlock-truncate/</guid>
      <pubDate>Mon, 20 Feb 2023 21:20:00 +0100</pubDate>
    </item>
    <item>
      <title>Why use Go-Landlock for sandboxing?</title>
      <link>https://blog.gnoack.org/post/go-landlock-talk</link>
      <description>&lt;ul id=&#34;toc&#34;&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#motivation&#34;&gt;Motivation&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#philosophy&#34;&gt;Philosophy&lt;/a&gt;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#the-landlock-approach&#34;&gt;The Landlock approach&lt;/a&gt;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#1-make-it-really-easy-to-use&#34;&gt;1. Make it really easy to use&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#2-make-sandboxing-enablement-part-of-program-initialization&#34;&gt;2. Make sandboxing enablement part of program initialization&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#other-operating-systems&#34;&gt;Other operating systems&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#other-linux-sandboxing-technologies&#34;&gt;Other Linux sandboxing technologies&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#how-to-use-go-landlock&#34;&gt;How to use Go-Landlock&lt;/a&gt;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#step-1-make-sure-your-kernel-supports-landlock&#34;&gt;Step 1: Make sure your kernel supports Landlock&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#step-2-state-what-file-accesses-you-are-going-to-do&#34;&gt;Step 2: State what file accesses you are going to do!&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#examples&#34;&gt;Examples&lt;/a&gt;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#image-converter&#34;&gt;Image converter&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#web-server&#34;&gt;Web Server&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#the-go-landlock-example-tool&#34;&gt;The Go-Landlock example tool&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#current-landlock-limitations&#34;&gt;Current Landlock limitations&lt;/a&gt;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#what-file-system-operations-are-restrictable&#34;&gt;What file system operations are restrictable?&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#summary&#34;&gt;Summary&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;a href=&#34;#further-links&#34;&gt;Further Links&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;This is the article version of a talk I presented a the Zurich&#xA;Gophers Meetup on 2022-10-25, with some less relevant parts&#xA;shortened.&lt;/p&gt;&#xA;&lt;p&gt;The slides are also available at&#xA;&lt;a href=&#34;https://blog.gnoack.org/talks/go-landlock&#34;&gt;https://blog.gnoack.org/talks/go-landlock&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;style&gt;&#xA;img { border-radius: 1em; border: 1px solid #0001; }&#xA;&lt;/style&gt;&#xA;&lt;h2 id=&#34;motivation&#34;&gt;Motivation&lt;/h2&gt;&#xA;&lt;p&gt;I started to get interested in computer security about 20 years ago.&#xA;In the late 90&amp;rsquo;s and early 2000&amp;rsquo;s, buffer overflow exploits were all&#xA;the rage and started to be more widely understood and researched.&lt;/p&gt;&#xA;&lt;p&gt;This image depicts a high level overview over a common pattern of a&#xA;technical attack (&amp;ldquo;exploit&amp;rdquo;) on a computer program:&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/talks/go-landlock/Go-Landlock-1.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;The attack channel can take many forms, such as&#xA;over the network, by invoking a privileged executable file, or by&#xA;distributing crafted input files.&lt;/div&gt;&#xA;The attacker talks to the attacked process through the same channels&#xA;like any other user would do. But unlike another user&#39;s input, the&#xA;attacker&#39;s input is maliciously crafted to trick the attacked process&#xA;into misinterpreting or wrongly validating it, and thereby doing&#xA;things on behalf of the attacker that it was not originally designed&#xA;to do.&#xA;&lt;p&gt;This can range from exposing process-local memory (e.g.&#xA;&lt;a href=&#34;https://en.wikipedia.org/wiki/Heartbleed&#34;&gt;Heartbleed&lt;/a&gt;), to exposing&#xA;the contents of files that were not intended to be exposed (e.g.&#xA;&lt;a href=&#34;https://en.wikipedia.org/wiki/Directory_traversal_attack&#34;&gt;directory traversal&#xA;attacks&lt;/a&gt;),&#xA;to even giving the attacker full control over the attacked process&#xA;(e.g. a &lt;a href=&#34;https://en.wikipedia.org/wiki/Buffer_overflow#Exploitation&#34;&gt;classic buffer overflow&#xA;exploit&lt;/a&gt;).&lt;/p&gt;&#xA;&lt;p&gt;Now all of this would be less critical, if the attacked process only&#xA;had access to the resources that it needs for execution, but as it&#xA;turns out, in the normal UNIX model, access rights are usually&#xA;determined by the user that a program runs as, and that often means&#xA;that these programs have access to significantly more things than they&#xA;need. (&lt;a href=&#34;https://en.wikipedia.org/wiki/Ambient_authority&#34;&gt;Ambient&#xA;Authority&lt;/a&gt;).&lt;/p&gt;&#xA;&lt;p&gt;For instance, programs that you run on your desktop are going to have&#xA;access to your bank documents, your (hopefully encrypted) SSH and PGP&#xA;keys, your cookies, your git repositories, etc.&lt;/p&gt;&#xA;&lt;p&gt;&amp;ndash; so: &lt;strong&gt;Let&amp;rsquo;s limit this ambient access!&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;philosophy&#34;&gt;Philosophy&lt;/h2&gt;&#xA;&lt;p&gt;I can&amp;rsquo;t speak for Mickaël Salaün&amp;rsquo;s vision for sandboxing, but this is&#xA;mine, and it aligns very well with Landlock&amp;rsquo;s approach.&lt;/p&gt;&#xA;&lt;p&gt;First of all, I hold the belief that:&lt;/p&gt;&#xA;&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;&lt;strong&gt;Software authors are generally well-meaning&lt;/strong&gt;. They want their&#xA;software to work, and to be secure. If provided with the right tools&#xA;for securing applications, they will use them.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;However, if we take a look at the adoption of unprivileged sandboxing&#xA;on Linux (namely, seccomp-bpf), it shows that there are only a handful&#xA;of programs making use of it &amp;ndash; but what is the reason for that?&lt;/p&gt;&#xA;&lt;p&gt;Which leads me to this hypothesis:&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/talks/go-landlock/Go-Landlock-4.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;&lt;strong&gt;It is too difficult&lt;/strong&gt; for software authors to confine their software&#xA;to have &lt;em&gt;just&lt;/em&gt; the access that the software needs, even though these&#xA;software authors are in the best position to reason about the required&#xA;scope of access.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h3 id=&#34;the-landlock-approach&#34;&gt;The Landlock approach&lt;/h3&gt;&#xA;&lt;p&gt;There are two main points that I&amp;rsquo;d like to push for in Go-Landlock,&#xA;which I think make it more usable for sandboxing than other&#xA;approaches:&lt;/p&gt;&#xA;&lt;h4 id=&#34;1-make-it-really-easy-to-use&#34;&gt;1. Make it really easy to use&lt;/h4&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/talks/go-landlock/Go-Landlock-5.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;The existing confinement approaches on Linux tend to be too difficult&#xA;to set up or maintain, which means that they don&amp;rsquo;t get used as much as&#xA;they should.&lt;/p&gt;&#xA;&lt;h4 id=&#34;2-make-sandboxing-enablement-part-of-program-initialization&#34;&gt;2. Make sandboxing enablement part of program initialization&lt;/h4&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/talks/go-landlock/Go-Landlock-6.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;This is the other main idea &amp;ndash; it should be up to each process to&#xA;enable its own sandbox.&lt;/p&gt;&#xA;&lt;p&gt;The rough approach is:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The program &lt;strong&gt;initializes itself&lt;/strong&gt; &amp;ndash; parses flags, opens the necessary files, named UNIX sockets, etc.&lt;/li&gt;&#xA;&lt;li&gt;The program &lt;strong&gt;restricts its own access&lt;/strong&gt; (using Landlock)&lt;/li&gt;&#xA;&lt;li&gt;The program &lt;strong&gt;starts processing untrusted input&lt;/strong&gt; from potentially malicious sources&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;Note: &lt;strong&gt;If programs sandbox themselves, they can drop more permissions&lt;/strong&gt;,&#xA;because they can also drop the permissions that were required for&#xA;their initialization phase.&lt;/p&gt;&#xA;&lt;p&gt;UNIX enforces permissions when &lt;em&gt;opening&lt;/em&gt; files, so an already opened&#xA;file can continue to get used by a process, even when it does not have&#xA;the permissions to open the file again.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h3 id=&#34;other-operating-systems&#34;&gt;Other operating systems&lt;/h3&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/talks/go-landlock/Go-Landlock-7.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;These ideas are not new - OpenBSD has demonstrated the feasability of&#xA;this approach with &lt;code&gt;pledge()&lt;/code&gt; and &lt;code&gt;unveil()&lt;/code&gt;, which is now used in&#xA;&lt;a href=&#34;https://github.com/openbsd/src/search?l=C&amp;amp;q=unveil&#34;&gt;many of OpenBSD&amp;rsquo;s userland&#xA;programs&lt;/a&gt;. Various&#xA;slide decks on the topic can be found at&#xA;&lt;a href=&#34;https://www.openbsd.org/events.html&#34;&gt;https://www.openbsd.org/events.html&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://wiki.freebsd.org/Capsicum&#34;&gt;Capsicum on FreeBSD&lt;/a&gt; is another&#xA;unprivileged sandboxing mechanism, which is used in Chromium and other&#xA;programs (see its homepage). Capsicum is a flexible capability system,&#xA;but it also has a larger API surface.&lt;/p&gt;&#xA;&lt;h3 id=&#34;other-linux-sandboxing-technologies&#34;&gt;Other Linux sandboxing technologies&lt;/h3&gt;&#xA;&lt;p&gt;A deeper discussion of seccomp-bpf and the various Linux Security&#xA;Modules would be beyond the scope of this article.&lt;/p&gt;&#xA;&lt;p&gt;For a discussion of the other unprivileged sandboxing mechanism, see&#xA;&lt;a href=&#34;https://blog.gnoack.org/post/pledge-on-linux/&#34;&gt;my previous article about&#xA;it&lt;/a&gt; on this blog.&lt;/p&gt;&#xA;&lt;p&gt;The other Linux sandboxing mechanisms are either only available to&#xA;privileged users, or they are still very difficult to set up.&lt;/p&gt;&#xA;&lt;h2 id=&#34;how-to-use-go-landlock&#34;&gt;How to use Go-Landlock&lt;/h2&gt;&#xA;&lt;p&gt;This diagram shows the overall approach for program initialization&#xA;when using Landlock (it&amp;rsquo;s a more detailed view of the program&#xA;initialization overview diagram from above):&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/talks/go-landlock/Go-Landlock-10.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;The important parts here are:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Primarily, &lt;strong&gt;Landlock is a Linux kernel feature&lt;/strong&gt; &amp;ndash; the access&#xA;policies enforced through Landlock apply to both the enforcing&#xA;program, as well as all newly forked subprocesses, independent of&#xA;the libraries being used to do these accesses.&lt;/li&gt;&#xA;&lt;li&gt;The &lt;strong&gt;Go-Landlock library is only required to configure and enforce&#xA;the Landlock policy&lt;/strong&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The steps required to enforce Landlock are:&lt;/p&gt;&#xA;&lt;h3 id=&#34;step-1-make-sure-your-kernel-supports-landlock&#34;&gt;Step 1: Make sure your kernel supports Landlock&lt;/h3&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/talks/go-landlock/Go-Landlock-11.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;&lt;strong&gt;For development&lt;/strong&gt;, it&amp;rsquo;s recommended to double check that Landlock is&#xA;already working, so that you can try out your policies. Landlock is&#xA;already enabled on many major distributions today.&lt;/p&gt;&#xA;&lt;p&gt;On most systems, you can check whether Landlock is working using &lt;code&gt;cat /sys/kernel/security/lsm&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;On systems that do not have it yet:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Make sure Landlock is compiled into the kernel.&lt;/li&gt;&#xA;&lt;li&gt;Set the &lt;code&gt;lsm=landlock&lt;/code&gt; boot parameter (or configure it in&#xA;&lt;code&gt;CONFIG_LSM&lt;/code&gt; at build time).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;strong&gt;For deployment&lt;/strong&gt;, you can pick whether your program should insist on&#xA;running on a Landlock-enabled kernel, or whether it should fall back&#xA;to using weaker (or no) Landlock policies on older systems:&lt;/p&gt;&#xA;&lt;h3 id=&#34;step-2-state-what-file-accesses-you-are-going-to-do&#34;&gt;Step 2: State what file accesses you are going to do!&lt;/h3&gt;&#xA;&lt;p&gt;This is the only function invocation your program needs in order to&#xA;confine itself in a Landlock policy:&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/talks/go-landlock/Go-Landlock-12.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;landlock.V2&lt;/code&gt;&lt;/strong&gt; determines the Landlock ABI version. A higher ABI&#xA;version means that more operations can be restricted.&#xA;(Alternatively, you can also spell out the exact operations that you&#xA;want to restrict.)&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;.BestEffort()&lt;/code&gt;&lt;/strong&gt; is an optional call &amp;ndash; it configures the library to&#xA;gracefully degrade to weaker Landlock policies on systems that do&#xA;not have the requested Landlock features.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;.RestrictPaths()&lt;/code&gt;&lt;/strong&gt; is the final call which enforces the rules.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;The arguments to &lt;code&gt;.RestrictPaths()&lt;/code&gt;&lt;/strong&gt; are file system hierarchies&#xA;that the process intends to still access going forward. Access to&#xA;all paths other than the listed ones will be forbidden, as much as&#xA;the Landlock ABI permits. (Landlock does not currently restrict&#xA;&lt;em&gt;all&lt;/em&gt; possible file system operations, but that&amp;rsquo;s eventually the&#xA;goal. A more detailed look is in the appendix below.)&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;landlock.RODirs&lt;/code&gt; and &lt;code&gt;landlock.RWDirs&lt;/code&gt;&lt;/strong&gt; are shortcuts to&#xA;identify &amp;ldquo;general read-only&amp;rdquo; operations and &amp;ldquo;general read-write&#xA;operations&amp;rdquo;. This can also be configured in more detail if needed.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&amp;hellip;and that&amp;rsquo;s it. After this invocation, your program will be unable&#xA;to work with files other than the ones specified or the ones that have&#xA;already been opened before.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://pkg.go.dev/github.com/landlock-lsm/go-landlock/landlock&#34;&gt;Link to the full documentation&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;examples&#34;&gt;Examples&lt;/h2&gt;&#xA;&lt;p&gt;This section will list a few practical examples.&lt;/p&gt;&#xA;&lt;h3 id=&#34;image-converter&#34;&gt;Image converter&lt;/h3&gt;&#xA;&lt;p&gt;This is a basic image conversion tool in the spirit of ImageMagick&amp;rsquo;s&#xA;&amp;ldquo;convert&amp;rdquo;. Multimedia processing libraries are often optimized for&#xA;performance and can be particularly prone to programming bugs, and we&#xA;want to protect against attackers providing malicious image files as&#xA;input.&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/talks/go-landlock/Go-Landlock-13.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;In this example, the Landlock invocation happens right at the start&#xA;and is &lt;code&gt;landlock.V2.BestEffort().RestrictPaths()&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;We simply restrict to &lt;strong&gt;no file system access at all&lt;/strong&gt;.&lt;/li&gt;&#xA;&lt;li&gt;But we fall back to enforcing weaker Landlock policies or none, if&#xA;it&amp;rsquo;s not supported by the system where the program is running.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/landlock-lsm/go-landlock/blob/main/examples/convert/main.go&#34;&gt;Link to the full example&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;web-server&#34;&gt;Web Server&lt;/h3&gt;&#xA;&lt;p&gt;This simple wiki software only needs access to the directory where the&#xA;wiki pages are stored.&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/talks/go-landlock/Go-Landlock-14.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;The Go-Landlock invocation is:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;err = landlock.V2.BestEffort().RestrictPaths(&#xA;    landlock.RWDirs(*storeDir),&#xA;)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This gives the process the right to serve and edit the wiki pages, but&#xA;removes the rights for all other file paths (within the limits of what&#xA;is possible on the current system).&lt;/p&gt;&#xA;&lt;p&gt;(Small side note: The &lt;code&gt;net.Listen()&lt;/code&gt; call happens before Landlock&#xA;enablement &amp;ndash; I am using this with a named UNIX domain socket.)&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/gnoack/ukuleleweb/blob/main/cmd/ukuleleweb/main.go&#34;&gt;Link to the full example&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;the-go-landlock-example-tool&#34;&gt;The Go-Landlock example tool&lt;/h3&gt;&#xA;&lt;p&gt;The Go-landlock library comes with a simple example tool, which lets&#xA;you play with Landlock from bash, similar to the one in the&#xA;&lt;code&gt;samples/landlock&lt;/code&gt; subdirectory in the kernel source, but written&#xA;using the Go library:&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/talks/go-landlock/Go-Landlock-15.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;The command to install the &lt;code&gt;landlock-restrict&lt;/code&gt; tool is:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;go install github.com/landlock-lsm/go-landlock/cmd/landlock-restrict@latest&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The above shell transcript starts &lt;code&gt;bash&lt;/code&gt; under a Landlock policy where&#xA;it only has access to these files:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Read access to &lt;code&gt;/usr&lt;/code&gt; and &lt;code&gt;/lib&lt;/code&gt;&lt;/strong&gt; is needed for shared libraries&#xA;and the &lt;code&gt;bash&lt;/code&gt; executable itself.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Read access to &lt;code&gt;/etc&lt;/code&gt;&lt;/strong&gt; is required for some common configuration&#xA;files.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Write access to &lt;code&gt;/dev&lt;/code&gt;&lt;/strong&gt; is needed for some specific files like&#xA;&lt;code&gt;/dev/null&lt;/code&gt;, &lt;code&gt;/dev/stdout&lt;/code&gt; and others. (Could be made more specific.)&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Write access to $HOME&lt;/strong&gt;: We rewire the &lt;code&gt;$HOME&lt;/code&gt; environment&#xA;variable to a temporary directory for our subprocess and set&#xA;&lt;code&gt;$TMPDIR&lt;/code&gt; to a directory within it, so we can just grant write&#xA;access to &lt;code&gt;$HOME&lt;/code&gt;. (This trick makes it possible to use a coarser&#xA;policy, but it lets the sandboxes process execute in a slightly less&#xA;usual environment.)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/landlock-lsm/go-landlock/blob/main/cmd/landlock-restrict/main.go&#34;&gt;Link to the &lt;code&gt;landlock-restrict&lt;/code&gt; example tool&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;current-landlock-limitations&#34;&gt;Current Landlock limitations&lt;/h2&gt;&#xA;&lt;p&gt;Some things that Landlocked processes can never do are:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;They can not &lt;strong&gt;manipulate the file system topology&lt;/strong&gt; (e.g. &lt;code&gt;mount&lt;/code&gt;, &lt;code&gt;pivot_root&lt;/code&gt;)&lt;/li&gt;&#xA;&lt;li&gt;Landlocked processes have the &lt;strong&gt;&lt;code&gt;NO_NEW_PRIVS&lt;/code&gt; flag&lt;/strong&gt; &amp;ndash; you can not execute suid root binaries&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Restricted use of &lt;code&gt;ptrace()&lt;/code&gt;&lt;/strong&gt; (debugging other processes)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Also,&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Landlock is &lt;em&gt;in development&lt;/em&gt;&lt;/li&gt;&#xA;&lt;li&gt;Some file operations are not restrictable yet&lt;/li&gt;&#xA;&lt;li&gt;But it&amp;rsquo;s already limiting the most common ones and it&amp;rsquo;s already usable&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;what-file-system-operations-are-restrictable&#34;&gt;What file system operations are restrictable?&lt;/h3&gt;&#xA;&lt;p&gt;Landlock gains features and makes it possible to restrict more file&#xA;system operations. To make this observable, Landlock&amp;rsquo;s ABI is&#xA;versioned. As of November 2022, the current ABI is V2.&lt;/p&gt;&#xA;&lt;p&gt;The list of restrictable file system operations is &lt;a href=&#34;https://docs.kernel.org/userspace-api/landlock.html#filesystem-flags&#34;&gt;documented in the&#xA;Landlock&#xA;documentation&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;blockquote class=&#34;warning&#34;&gt;&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: Not all file system operations can be restricted&#xA;yet. Currently, notable exceptions are file truncation (as a form of&#xA;file modification), and various ways to observe presence and metadata&#xA;of files (but not reading their contents).&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;In future Landlock ABI versions, new operations will start to be&#xA;configurable. Currently ongoing patch sets (as of November 2022) are:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;File truncation (currently scheduled for inclusion in kernel 6.2)&lt;/li&gt;&#xA;&lt;li&gt;Chmod and Chown (patch set in review)&lt;/li&gt;&#xA;&lt;li&gt;Networking support (patch set in review)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;summary&#34;&gt;Summary&lt;/h2&gt;&#xA;&lt;p&gt;In short, please try it out! The invocation is as simple as:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;err := landlock.V2.BestEffort().RestrictPaths(&#xA;    landlock.RODirs(&amp;quot;/usr&amp;quot;, &amp;quot;/bin&amp;quot;),&#xA;    landlock.RWDirs(&amp;quot;/tmp&amp;quot;),&#xA;)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;I would love to hear your feedback!&lt;/p&gt;&#xA;&lt;h2 id=&#34;further-links&#34;&gt;Further Links&lt;/h2&gt;&#xA;&lt;p&gt;For further reference, here are some additional links:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Go-Landlock:&#xA;&lt;ul&gt;&#xA;&lt;li&gt;On Github: &lt;a href=&#34;https://github.com/landlock-lsm/go-landlock&#34;&gt;https://github.com/landlock-lsm/go-landlock&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;Docs: &lt;a href=&#34;https://pkg.go.dev/github.com/landlock-lsm/go-landlock/landlock&#34;&gt;https://pkg.go.dev/github.com/landlock-lsm/go-landlock/landlock&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Landlock kernel project:&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Page: &lt;a href=&#34;https://landlock.io/&#34;&gt;https://landlock.io/&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;Kernel doc: &lt;a href=&#34;https://docs.kernel.org/userspace-api/landlock.html&#34;&gt;https://docs.kernel.org/userspace-api/landlock.html&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Mailing list: &lt;a href=&#34;https://lore.kernel.org/landlock&#34;&gt;https://lore.kernel.org/landlock&lt;/a&gt; (To subscribe, mail&#xA;&lt;a href=&#34;mailto:landlock+subscribe@lists.linux.dev&#34;&gt;landlock+subscribe@lists.linux.dev&lt;/a&gt;)&lt;/li&gt;&#xA;&lt;li&gt;Some more documentation:&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://docs.google.com/document/d/1SkFpl_Xxyl4E6G2uYIlzL0gY2PFo-Nl8ikblLvnpvlU/edit&#34;&gt;Landlock File System Access&#xA;Model&lt;/a&gt;&#xA;(discussing the kernel API and configurable file system operations&#xA;in a more mathematical way).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/go-landlock-talk/</guid>
      <pubDate>Mon, 14 Nov 2022 20:00:00 +0100</pubDate>
    </item>
    <item>
      <title>The feasibility of pledge() on Linux</title>
      <link>https://blog.gnoack.org/post/pledge-on-linux</link>
      <description>&lt;p&gt;So, there was a &lt;a href=&#34;https://justine.lol/pledge/&#34;&gt;post by Justine Tunney&lt;/a&gt;&#xA;about her port of &lt;a href=&#34;https://man.openbsd.org/pledge.2&#34;&gt;OpenBSD&amp;rsquo;s&#xA;&lt;code&gt;pledge()&lt;/code&gt;&lt;/a&gt; to her own libc, the&#xA;&lt;a href=&#34;https://justine.lol/cosmopolitan/&#34;&gt;Cosmopolitan libc&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;She is also calling out that previous attempts at this were flawed:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;There&amp;rsquo;s been a few devs in the past who&amp;rsquo;ve tried this. I&amp;rsquo;m not going to name names, because most of these projects were never completed. [&amp;hellip;] The projects that got further along also had oversights like allowing the changing of setuid/setgid/sticky bits. So none of the current alternatives should be used.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;My own &lt;a href=&#34;https://github.com/gnoack/seccomp-scopes&#34;&gt;seccomp-scopes&lt;/a&gt;&#xA;project which I worked on from 2016 onwards is one of these attempts,&#xA;so I feel I should explain the reasons &lt;em&gt;why&lt;/em&gt; I stopped pursuing this&#xA;approach of unprivileged sandboxing, and what I think needs to get&#xA;done to do it right.&lt;/p&gt;&#xA;&lt;p&gt;At the high level, the main problem is that seccomp-bpf does its&#xA;filtering at the level of system calls and &lt;strong&gt;software libraries&#xA;generally do not give guarantees about which system calls they are&#xA;using under the hood&lt;/strong&gt;. This does not even hold for &lt;code&gt;libc&lt;/code&gt;&#xA;implementations.&lt;/p&gt;&#xA;&lt;h2 id=&#34;you-cant-predict-the-syscalls-a-program-will-do&#34;&gt;You can&amp;rsquo;t predict the syscalls a program will do&lt;/h2&gt;&#xA;&lt;p&gt;Here are some ways in which glibc makes it hard to predict which&#xA;system calls it will do:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;glibc replaces existing uses of system calls with newer variants. A&#xA;call to the &lt;code&gt;open()&lt;/code&gt; libc function used the &lt;code&gt;openat(2)&lt;/code&gt; syscall&#xA;under the hood, and that is just one of many examples. This changes&#xA;between glibc versions.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;glibc initializes parts of the library on demand when they are first&#xA;used, and that may involve system calls that should better be&#xA;forbidden. So this initialization needs to ideally be done before&#xA;enforcing seccomp.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;glibc makes use of shared libraries for commonly used functionality&#xA;(&lt;a href=&#34;https://man7.org/linux/man-pages/man5/nsswitch.conf.5.html&#34;&gt;&lt;code&gt;nsswitch.conf&lt;/code&gt;&lt;/a&gt;).&#xA;Administrators can flexibly install additional ways of doing name&#xA;lookups, but any attempt at reasoning about this will need to&#xA;involve these shared libraries as well.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;For example: If a program calls &lt;code&gt;gethostbyname()&lt;/code&gt; for the first time, the following things happen:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;It looks up &lt;code&gt;/etc/nsswitch.conf&lt;/code&gt; to find the shared libraries that implement hostname lookup (system calls: various file accesses)&lt;/li&gt;&#xA;&lt;li&gt;It loads these shared libraries (system calls: various file accesses, various address space manipulation syscalls)&lt;/li&gt;&#xA;&lt;li&gt;It calls these shared libraries to do name lookup (system calls: you can&amp;rsquo;t tell anymore)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;There is additionally the problem that at the system call layer, DNS&#xA;lookups are indistinguishable from other UDP socket operations, so&#xA;allow-listing DNS will probably allow other UDP traffic as well.&lt;/p&gt;&#xA;&lt;p&gt;So, to summarize: Attempting to implement a &lt;code&gt;pledge()&lt;/code&gt; like call with&#xA;seccomp-bpf and independent of a specific libc is an inherently&#xA;brittle approach, which &lt;strong&gt;involves keeping up-to-date lists of system&#xA;calls on different kernel versions and architectures and their use by&#xA;different libcs&lt;/strong&gt;. The complexity and feature-richness of glibc&#xA;(particularly libnss) makes this particularly difficult. Any&#xA;libc-independent &lt;code&gt;pledge()&lt;/code&gt; library would need to get updated in sync&#xA;with glibc updates, or it would run the risk that glibc starts using a&#xA;syscall that it doesn&amp;rsquo;t allow-list, breaking the programs that use it.&lt;/p&gt;&#xA;&lt;p&gt;Justine Tunney&amp;rsquo;s &lt;code&gt;pledge()&lt;/code&gt; implementation works around these problems&#xA;by (a) only supporting her own, simpler, libc implementation, and (b)&#xA;only supporting the x86-64 architecture. I&amp;rsquo;m really happy to see that&#xA;this works well together, but I&amp;rsquo;m afraid it&amp;rsquo;s a mistake to think this&#xA;implementation can be &amp;ldquo;ported&amp;rdquo; to glibc which is used for the bulk of&#xA;Linux distributions.&lt;/p&gt;&#xA;&lt;h2 id=&#34;restricting-by-file-path&#34;&gt;Restricting by file path&lt;/h2&gt;&#xA;&lt;p&gt;In OpenBSD, &lt;code&gt;pledge()&lt;/code&gt; was always path-aware, until they moved that&#xA;part into the separate &lt;code&gt;unveil()&lt;/code&gt; call.&lt;/p&gt;&#xA;&lt;p&gt;Seccomp-bpf can only filter syscalls by their direct arguments, so the&#xA;filter can see the value of the pointer to the path name, but not the&#xA;path name itself in the memory referenced by that pointer.&lt;/p&gt;&#xA;&lt;p&gt;There are more advanced techniques to inspect pointer memory, but&#xA;using these safely involves separate supervisor processes or more&#xA;complicated constrained ways to control what processes do &amp;ndash; you need&#xA;to take security very seriously pull that off, and doesn&amp;rsquo;t map to a&#xA;call to a single C function like &lt;code&gt;pledge()&lt;/code&gt; anymore.&lt;/p&gt;&#xA;&lt;h2 id=&#34;landlock-promises-to-fix-this-in-the-future&#34;&gt;Landlock promises to fix this in the future&lt;/h2&gt;&#xA;&lt;p&gt;Unprivileged sandboxing continues to be difficult on Linux, for the&#xA;moment, and it&amp;rsquo;s no surprise that the main users of seccomp-bpf are&#xA;either dedicated sandboxing or containerization tools, or projects&#xA;where security is a major focus, like web browsers, OpenSSH or Tor.&#xA;But we should not give up yet. :)&lt;/p&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://landlock.io/&#34;&gt;Landlock LSM&lt;/a&gt; offers a better approach for&#xA;unprivileged sandboxing, although it can&amp;rsquo;t currently restrict the same&#xA;number of operations yet as seccomp-bpf can.  Landlock can&#xA;solve the above problems, because:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Landlock filters security-sensitive operations at the point when&#xA;these operations are done in the kernel, not at the system call&#xA;layer. This makes it architecture independent and removes the&#xA;need to keep up-to-date lists of system calls.&lt;/li&gt;&#xA;&lt;li&gt;Landlock can easily filter on file paths and other relevant&#xA;in-memory properties that can not be observed by seccomp-bpf at the&#xA;system call interface.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;If you want to try it out, Landlock is already enabled on some Linux&#xA;distributions (i.e. Arch Linux). A simple call to Landlock (using the&#xA;Go library) is:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;err := landlock.V1.BestEffort().RestrictPaths(&#xA;    landlock.RODirs(&amp;quot;/usr&amp;quot;, &amp;quot;/bin&amp;quot;),&#xA;    landlock.RWDirs(&amp;quot;/tmp&amp;quot;),&#xA;)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Some further links:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://landlock.io&#34;&gt;https://landlock.io&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://pkg.go.dev/github.com/landlock-lsm/go-landlock/landlock&#34;&gt;documentation for Go-Landlock&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;summary&#34;&gt;Summary&lt;/h2&gt;&#xA;&lt;p&gt;As shown above, seccomp-bpf makes it more difficult than necessary to&#xA;sandbox processes. It is available on a wide range of Linux&#xA;distributions, but it&amp;rsquo;s currently not practical to use for the bulk of&#xA;software linked to glibc, and it&amp;rsquo;s not possible to restrict operations&#xA;by file path in BPF.&lt;/p&gt;&#xA;&lt;p&gt;Landlock is not rolled out to all Linux distributions yet, and it&#xA;still has some known gaps in its current version, but it has a&#xA;significantly simpler API and a much simpler implementation in the&#xA;kernel than what would be required in userspace to work around the&#xA;problems of seccomp-bpf.&lt;/p&gt;&#xA;&lt;p&gt;And simplicity is a great property for security features to have. I&#xA;can wholeheartedly recommend having a look at it.&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/pledge-on-linux/</guid>
      <pubDate>Sat, 16 Jul 2022 10:36:20 +0200</pubDate>
    </item>
    <item>
      <title>XKB With Sway</title>
      <link>https://blog.gnoack.org/post/xkb-with-sway</link>
      <description>&lt;p&gt;This explains how to configure multiple keyboards in Sway, and how to&#xA;use advanced configuration when regular &lt;code&gt;xkb_options&lt;/code&gt; are not enough.&lt;/p&gt;&#xA;&lt;h2 id=&#34;sway-configuration&#34;&gt;Sway configuration&lt;/h2&gt;&#xA;&lt;p&gt;Luckily, Sway has great support for multiple keyboards with different&#xA;layouts, so it nicely adjusts to whatever keyboard you have plugged in&#xA;or can use separate configurations for a physical keyboard and the&#xA;laptop keyboard.&lt;/p&gt;&#xA;&lt;p&gt;First, identify the identifiers for the keyboards you have plugged in,&#xA;using the following command:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ swaymsg -t get_inputs&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Look for the lines starting with &lt;code&gt;Identifier:&lt;/code&gt; for the device you&amp;rsquo;re&#xA;interested in.&lt;/p&gt;&#xA;&lt;p&gt;Next, add one section for each of your keyboards to &lt;code&gt;~/.config/sway/config&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;input &amp;quot;1278:32:PFU_Limited_HHKB-Classic&amp;quot; {&#xA;&#x9;xkb_layout &amp;quot;us&amp;quot;&#xA;&#x9;xkb_model &amp;quot;hhk&amp;quot;&#xA;&#x9;xkb_options &amp;quot;compose:ralt&amp;quot;&#xA;&#x9;xkb_capslock &amp;quot;disabled&amp;quot;&#xA;}&#xA;&#xA;input &amp;quot;1133:49948:Logitech_USB_Keyboard&amp;quot; {&#xA;&#x9;xkb_file &amp;quot;.xkb/keymap/logitech&amp;quot;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The example above lists a HHKB (&amp;ldquo;Happy Hacking&amp;rdquo;) keyboard where right&#xA;Alt acts as the Compose key. More options are documented in the man&#xA;pages &lt;a href=&#34;https://manned.org/sway-input.5&#34;&gt;sway-input(5)&lt;/a&gt; as well as&#xA;&lt;a href=&#34;https://manned.org/xkeyboard-config.7&#34;&gt;xkeyboard-config(7)&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;In the case where the existing XKB options are not sufficient, you&#xA;need to refer to a separate XKB configuration file, as described below.&lt;/p&gt;&#xA;&lt;h2 id=&#34;xkb-configuration&#34;&gt;XKB configuration&lt;/h2&gt;&#xA;&lt;p&gt;To configure my Logitech keyboard, the plan was to have the key&#xA;mapping reasonably close to the HHKB layout.&lt;/p&gt;&#xA;&lt;p&gt;In my case, I have two files under &lt;code&gt;~/.xkb&lt;/code&gt; (the directories need to&#xA;first be created): This is the &lt;code&gt;~/.xkb/keymap/logitech&lt;/code&gt; file:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;// Derived from `setxkbmap -print`,&#xA;// added the &amp;quot;+unixy&amp;quot; part to xkb_symbols.&#xA;xkb_keymap {&#xA;&#x9;xkb_keycodes  { include &amp;quot;evdev+aliases(qwerty)&amp;quot;&#x9;};&#xA;&#x9;xkb_types     { include &amp;quot;complete&amp;quot;&#x9;};&#xA;&#x9;xkb_compat    { include &amp;quot;complete&amp;quot;&#x9;};&#xA;&#x9;xkb_symbols   { include &amp;quot;pc+us+inet(evdev)+unixy&amp;quot;&#x9;};&#xA;&#x9;xkb_geometry  { include &amp;quot;pc(pc105)&amp;quot;&#x9;};&#xA;};&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This file is the output from running &lt;code&gt;setxkbmap -print&lt;/code&gt;, but adds the&#xA;&lt;code&gt;+unixy&lt;/code&gt; part to the &lt;code&gt;xkb_symbols&lt;/code&gt; section. This refers to the&#xA;&lt;code&gt;~/.xkb/symbols/unixy&lt;/code&gt; file with the following content:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;partial alphanumeric_keys&#xA;xkb_symbols &amp;quot;unixy&amp;quot; {&#xA;&#x9;// exchange backspace and backslash&#xA;&#x9;key &amp;lt;BKSL&amp;gt; {&#x9;[ BackSpace, Backspace ] };&#xA;&#x9;key &amp;lt;BKSP&amp;gt; {&#x9;[ backslash, bar ] };&#xA;&#xA;&#x9;// caps is ctrl&#xA;&#x9;key &amp;lt;CAPS&amp;gt; {&#x9;[ Control_L ] };&#xA;&#x9;modifier_map Control { &amp;lt;CAPS&amp;gt; };&#xA;&#xA;&#x9;// right alt is compose&#xA;&#x9;key &amp;lt;RALT&amp;gt; {&#x9;[ Multi_key ] };&#xA;};&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/xkb-with-sway/</guid>
      <pubDate>Thu, 02 Dec 2021 18:24:17 +0100</pubDate>
    </item>
    <item>
      <title>Error Handling Links</title>
      <link>https://blog.gnoack.org/post/error-handling-links</link>
      <description>&lt;p&gt;This is a collection of interesting literature on the subject of error&#xA;handling which I had collected to research &lt;a href=&#34;https://blog.gnoack.org/post/error_handling/&#34;&gt;my own blog post on the&#xA;subject&lt;/a&gt; a while ago.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&amp;ldquo;&lt;a href=&#34;https://www.amazon.com/Philosophy-Software-Design-John-Ousterhout/dp/1732102201&#34;&gt;A Philosophy of Software&#xA;Design&lt;/a&gt;&amp;rdquo;&#xA;by John Ousterhout has a significant section on error handling that&#xA;I found worth a read. It takes a slightly different angle and gives&#xA;some good examples on how to design programs in a way so that errors&#xA;cannot happen, or only happen in the right places.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://www.amazon.com/Smalltalk-80-Language-Implementation-Adele-Goldberg/dp/0201113716/&#34;&gt;Smalltalk-80 Blue&#xA;book&lt;/a&gt;&#xA;had the weirdest error handling mechanism: You&amp;rsquo;d call the &lt;code&gt;error:&lt;/code&gt;&#xA;method on your own object, and the interactive system pops up a&#xA;dialog. Some Smalltalk errors are recoverable in unusual ways&#xA;through the interactivity of the system - you can define methods on&#xA;the go if your program calls a method that doesn&amp;rsquo;t exist&amp;hellip; :)&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Common Lisp has a &amp;ldquo;Conditions&amp;rdquo; system which is similar to exceptions&#xA;in that it propagates up the stack, but it inserts a layer in the&#xA;middle between handling (&amp;ldquo;catching&amp;rdquo;) and signaling (&amp;ldquo;raising&amp;rdquo;)&#xA;exceptions. The middle layer can define recovery strategies which&#xA;the handling layer can then choose from.&lt;/p&gt;&#xA;&lt;p&gt;I found the Common Lisp stuff in the &amp;ldquo;&lt;a href=&#34;https://gigamonkeys.com/book/&#34;&gt;Practical Common&#xA;Lisp&lt;/a&gt;&amp;rdquo; book. I cannot claim that I&#xA;managed to wrap my head around that one. The chapter is online at&#xA;&lt;a href=&#34;https://gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html&#34;&gt;https://gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html&lt;/a&gt;&#xA;. Apparently someone wrote a full book on the Common Lisp condition&#xA;system recently, but I haven&amp;rsquo;t read that.&#xA;&lt;a href=&#34;https://amazon.com/Common-Lisp-Condition-System-Mechanisms/dp/148426133X&#34;&gt;https://amazon.com/Common-Lisp-Condition-System-Mechanisms/dp/148426133X&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Apart from that, the books I looked through were not very helpful. I&#xA;feel that the Ousterhout approach of explaining this is a useful one,&#xA;talking about ways to design programs so that the complications of&#xA;error handling are reduced.&lt;/p&gt;&#xA;&lt;p&gt;Other notable &amp;ldquo;error handling philosophies&amp;rdquo; I have only some links to&amp;hellip;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://python.org/dev/peps/pep-0020/&#34;&gt;https://python.org/dev/peps/pep-0020/&lt;/a&gt; The Zen of Python (&amp;ldquo;errors&#xA;should never pass silently&amp;rdquo;)&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;The Midori error model&#xA;&lt;a href=&#34;http://joeduffyblog.com/2016/02/07/the-error-model/&#34;&gt;http://joeduffyblog.com/2016/02/07/the-error-model/&lt;/a&gt; (Midori was an&#xA;experimental OS developed at Microsoft)&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;My own research culminated in this article:&#xA;&lt;a href=&#34;https://blog.gnoack.org/post/error_handling/&#34;&gt;https://blog.gnoack.org/post/error_handling/&lt;/a&gt;. In hindsight, I took a&#xA;much too academic and prescriptive approach there, and so it doesn&amp;rsquo;t&#xA;get read much. The article might be biased towards the &amp;ldquo;deployed and&#xA;monitored&amp;rdquo; kind of software.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Another thing I heard people discuss is the rule to &amp;ldquo;act on an error&#xA;in only one place&amp;rdquo;, but I failed to find a canonical source for it.&#xA;(It&amp;rsquo;s the rule that is most commonly violated if someone is logging&#xA;the same error at multiple layers in the stack, leading to log spam.)&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/error-handling-links/</guid>
      <pubDate>Fri, 10 Sep 2021 16:54:54 +0200</pubDate>
    </item>
    <item>
      <title>Sandboxing with Landlock</title>
      <link>https://blog.gnoack.org/post/landlock</link>
      <description>&lt;p&gt;Linux 5.13 is going to include the unprivileged sandboxing feature&#xA;Landlock, which has been in the making for many years now.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;Unprivileged&lt;/em&gt; means that you don&amp;rsquo;t need special system-level&#xA;privileges like &lt;code&gt;root&lt;/code&gt; or &lt;code&gt;CAP_MAC_ADMIN&lt;/code&gt; to use it, as some other&#xA;Linux sandboxing mechanisms do. Philosophically speaking, you should&#xA;not need additional special privileges just to drop the privileges&#xA;that you already have.&lt;/p&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;How it works&lt;/div&gt;&#xA;&lt;p&gt;With Landlock, processes can restrict themselves to only use a&#xA;specified set of file paths, and it lets them control which operations&#xA;are available on these paths and their subdirectories (for example&#xA;opening for reading, writing, and directory operations&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;).&lt;/p&gt;&#xA;&lt;p&gt;A similar sandboxing feature has been around in OpenBSD for a while&#xA;now with &lt;code&gt;unveil()&lt;/code&gt;: &lt;a href=&#34;https://www.openbsd.org/papers/bsdcan2019-unveil/index.html&#34;&gt;This slide&#xA;deck&lt;/a&gt;&#xA;&lt;a href=&#34;https://www.youtube.com/watch?v=gvmGfpMgny4&#34;&gt;and talk&lt;/a&gt; by Bob Beck&#xA;talks about the lessons learned and has examples on how to sandbox&#xA;software with it, which should translate well to Landlock.&lt;/p&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;Download&lt;/div&gt;&#xA;&lt;p&gt;To make it easier to play with, I forked the Landlock example tool&#xA;from the kernel sources and made it compile standalone: You can get it&#xA;at&#xA;&lt;a href=&#34;https://github.com/gnoack/landlockjail&#34;&gt;https://github.com/gnoack/landlockjail&lt;/a&gt;,&#xA;or you can just download a &lt;a href=&#34;https://github.com/gnoack/landlockjail/releases/download/v1/lljail&#34;&gt;precompiled statically linked&#xA;version&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;At the moment, there are still some gaps, like &lt;code&gt;stat()&lt;/code&gt;,&#xA;which can still be done even in landlocked processes. But it&amp;rsquo;s moving&#xA;in the right direction, and at least accesses to the files&amp;rsquo; contents&#xA;can already be restricted.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/landlock/</guid>
      <pubDate>Fri, 16 Apr 2021 14:20:09 +0200</pubDate>
    </item>
    <item>
      <title>Writing Tests in Go</title>
      <link>https://blog.gnoack.org/post/go-tests</link>
      <description>&lt;div class=&#34;sidenote&#34;&gt;Tests should be correct by inspection&lt;/div&gt;&#xA;Tests require a different approach than normal code. We don&#39;t have&#xA;tests for tests, so tests need to be correct by inspection -- and the&#xA;main technique to achieve this is to get rid of the generality of the&#xA;production code, and exercise only very narrow and specific scenarios.&#xA;&lt;h1 id=&#34;decide-what-test-to-write&#34;&gt;Decide what test to write&lt;/h1&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;The goal of testing is to increase confidence&lt;/div&gt;&#xA;A test&#39;s purpose is to increase the confidence that you have in your&#xA;program&#39;s correctness. The next test to write is the test that&#xA;promises the highest ratio of additional confidence for the work&#xA;required to write it.&#xA;&lt;h2 id=&#34;do-test-all-your-business-decisions&#34;&gt;Do test all your business decisions&lt;/h2&gt;&#xA;&lt;p&gt;Test all your code that is testable. Prioritize testing the code that&#xA;(a) &lt;strong&gt;is important to work correctly&lt;/strong&gt; (where confidence needs to be&#xA;high) or (b) &lt;strong&gt;has become too complicated&lt;/strong&gt; (where confidence has&#xA;dropped too low).&lt;/p&gt;&#xA;&lt;h2 id=&#34;dont-test-io-and-side-effects&#34;&gt;Don&amp;rsquo;t test I/O and side effects&lt;/h2&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;Controversial part ahead!&lt;/div&gt;&#xA;Sometimes, production code will do I/O or other side effects that are&#xA;hard to simulate reproducably in a test. In these cases, it can&#xA;sometimes be advisable to separate the I/O parts of the production&#xA;code out and only test the rest - the bulk of your logic. It&#39;s key to&#xA;only separate out only the smallest possible part that has the side&#xA;effect, to keep as much as possible of the program testable.&#xA;&lt;p&gt;&amp;ldquo;But Günther&amp;rdquo;, I hear you saying, &amp;ldquo;what if there is a bug in these I/O&#xA;parts&amp;rdquo;? Well - that&amp;rsquo;s why you need to keep them tiny and stare at them&#xA;very long in a code review, to make sure they work without a test. It&#xA;sounds heretic to leave this untested, but the alternative is to keep&#xA;the I/O and other program logic together. That&amp;rsquo;ll easily make your&#xA;more regular program logic hard to test, and that&amp;rsquo;s often not worth&#xA;the trade off. After all, our goal is to increase confidence, not to&#xA;reach full line coverage.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Special case:&lt;/strong&gt; There are also some types of I/O which don&amp;rsquo;t affect&#xA;your program logic, such as logging and incrementing performance&#xA;counters. It&amp;rsquo;s ok to leave those untested without separating them&#xA;out - these are battle proof APIs designed for quickly adding and&#xA;removing them from your code, and they do not play a role for your&#xA;programs correctness. It would give you little additional confidence&#xA;to test them.&lt;/p&gt;&#xA;&lt;h1 id=&#34;structure-your-tests-into-givenwhenthen&#34;&gt;Structure your tests into Given/When/Then&lt;/h1&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;Stick to the three test phases!&lt;/div&gt;&#xA;&lt;p&gt;Stick with the setup/exercise/verify style of tests. Some people call&#xA;this also&#xA;&lt;a href=&#34;https://martinfowler.com/bliki/GivenWhenThen.html&#34;&gt;Given/When/Then&lt;/a&gt;&#xA;or the &lt;a href=&#34;http://xunitpatterns.com/Four%20Phase%20Test.html&#34;&gt;&amp;ldquo;Four Phase&#xA;test&amp;rdquo;&lt;/a&gt; (counting&#xA;tear-down as separate phase).&lt;/p&gt;&#xA;&lt;p&gt;It does not matter what you call this pattern, but &amp;ldquo;Given/When/Then&amp;rdquo;&#xA;tends to read nice in comments. Delimiting the section explicitly with&#xA;comments is optional, but serves another useful purpose: You cannot&#xA;use helper functions that span multiple of these purposes. (Those&#xA;helper functions would be bad style.)&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;func TestSpellOut(t *testing.T) {&#xA;  // Given&#xA;  s := speller.New(&amp;quot;en&amp;quot;)&#xA;&#xA;  // When&#xA;  got := s.SpellOut(42)&#xA;&#xA;  // Then&#xA;  want := &amp;quot;forty-two&amp;quot;&#xA;  if got != want {&#xA;    t.Errorf(&amp;quot;SpellOut(%q); got %q, want %q&amp;quot;, 42, got, want)&#xA;  }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h1 id=&#34;test-helpers&#34;&gt;Test helpers&lt;/h1&gt;&#xA;&lt;p&gt;Test helper functions should be the primary way to share functionality&#xA;between tests.&lt;/p&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;Each helper serves only one of the test phases&lt;/div&gt;&#xA;Make sure that each test helper helps with only one of the test&#xA;phases: setup, exercise or verify.&#xA;&lt;p&gt;In particular, resist the temptation to extract the whole test into a&#xA;helper method, so that you can call it with differing parameters. The&#xA;way this is done in Go instead is with &lt;a href=&#34;https://dave.cheney.net/2019/05/07/prefer-table-driven-tests&#34;&gt;table-driven&#xA;tests&lt;/a&gt;&#xA;and&#xA;&lt;a href=&#34;https://golang.org/pkg/testing/#hdr-Subtests_and_Sub_benchmarks&#34;&gt;&lt;code&gt;t.Run()&lt;/code&gt;&lt;/a&gt;&#xA;if needed.&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;setup-helpers&#34;&gt;Setup helpers&lt;/h2&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;The checklist for setup helpers&lt;/div&gt;&#xA;A setup helper is called from a test&#39;s setup phase and should have the&#xA;following properties:&#xA;&lt;ul&gt;&#xA;&lt;li&gt;It accepts a &lt;code&gt;testing.TB&lt;/code&gt;&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; as first parameter.&lt;/li&gt;&#xA;&lt;li&gt;It calls &lt;code&gt;t.Helper()&lt;/code&gt; at the start.&lt;/li&gt;&#xA;&lt;li&gt;It may not return an error, but will call &lt;code&gt;t.Fatal()&lt;/code&gt; on error.&#xA;&lt;ul&gt;&#xA;&lt;li&gt;It is ok to fail early in setup helpers.&lt;/li&gt;&#xA;&lt;li&gt;Tests don&amp;rsquo;t need to check errors manually, making them easier to read.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;If it sets up state that needs to be undone after the test, it calls&#xA;&lt;a href=&#34;/post/go-testing-cleanup&#34;&gt;&lt;code&gt;t.Cleanup()&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;This is a helper method for setting up a &lt;code&gt;Speller&lt;/code&gt; object from the&#xA;previous example:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;func setUpSpeller(t testing.TB, path string) speller.Speller {&#xA;  t.Helper()&#xA;&#xA;  s, err := speller.Load(path)&#xA;  if err != nil {&#xA;    t.Fatalf(&amp;quot;Could not set up speller: speller.Load(%q): %v&amp;quot;,&#xA;             path, err)&#xA;  }&#xA;&#xA;  t.Cleanup(s.Close)&#xA;  return s&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2 id=&#34;exercise-helpers&#34;&gt;Exercise helpers&lt;/h2&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;Don&#39;t.&lt;/div&gt;&#xA;Only introduce helpers for the test&#39;s execute phase if the invocation&#xA;is unbearable to read.&#xA;&lt;p&gt;It&amp;rsquo;s good practice to exercise the component under test directly&#xA;without such a helper. Using the component directly is a good test for&#xA;its API&amp;rsquo;s usability and will often uncover small possibilities for API&#xA;improvements in the process.&lt;/p&gt;&#xA;&lt;h2 id=&#34;verification-helpers&#34;&gt;Verification helpers&lt;/h2&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;Alternatives to assertion libraries&lt;/div&gt;&#xA;Common Go style discourages the use of assertion helper libraries,&#xA;which are common in most other languages.&#xA;&lt;p&gt;While I don&amp;rsquo;t necessarily agree with that, the next best thing you can&#xA;do within the bounds of this style is to extract helpers that do the&#xA;necessary comparisons for you, if necessary. The ground rule I use is:&#xA;The &lt;code&gt;if&lt;/code&gt; should be part of the top-level test function, but the&#xA;condition in that check can call the helper.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;These helpers do not need to have &lt;code&gt;testing.TB&lt;/code&gt; passed in - they are&#xA;just regular utility functions.&lt;/li&gt;&#xA;&lt;li&gt;They should probably return a boolean, or other object representing&#xA;the result of the check (like&#xA;&lt;a href=&#34;https://godoc.org/github.com/google/go-cmp/cmp#Diff&#34;&gt;&lt;code&gt;cmp.Diff&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h1 id=&#34;general-advice-on-writing-tests&#34;&gt;General advice on writing tests&lt;/h1&gt;&#xA;&lt;p&gt;A lot of general advice from other testing frameworks is applicable to&#xA;Go too.&lt;/p&gt;&#xA;&lt;h2 id=&#34;make-each-test-exercise-a-specific-narrow-scenario&#34;&gt;Make each test exercise a specific narrow scenario&lt;/h2&gt;&#xA;&lt;p&gt;Each test should exercise a specific and narrow scenario. There should&#xA;be little overlap between tests. Any bug introduced in the code should&#xA;ideally only break a single test, which has narrow focus and is&#xA;related to the broken functionality.&lt;/p&gt;&#xA;&lt;h3 id=&#34;start-with-the-assertion&#34;&gt;Start with the assertion&lt;/h3&gt;&#xA;&lt;p&gt;Start writing tests with the assertion, and work from there upwards by&#xA;filling out the missing variables that aren&amp;rsquo;t defined yet. This&#xA;approach helps me to focus each test around one specific and narrow&#xA;behaviour that I want to test.&lt;/p&gt;&#xA;&lt;h3 id=&#34;one-test-for-the-happy-path-plus-one-for-each-error&#34;&gt;One test for the happy path, plus one for each error&lt;/h3&gt;&#xA;&lt;p&gt;With simple functions with inputs, outputs and errors, I like to have&#xA;one main test for the happy path, plus one for each error, whose test&#xA;input is based on the one for the happy path, with a modification.&lt;/p&gt;&#xA;&lt;p&gt;See my article on &lt;a href=&#34;/post/base_fixture&#34;&gt;Shared base fixtures&lt;/a&gt; for examples.&lt;/p&gt;&#xA;&lt;h2 id=&#34;avoid-testmain-use-setup-helper-functions&#34;&gt;Avoid &lt;code&gt;TestMain&lt;/code&gt;, use setup helper functions&lt;/h2&gt;&#xA;&lt;p&gt;If you don&amp;rsquo;t know what &lt;code&gt;TestMain&lt;/code&gt; is, good!&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;TestMain&lt;/code&gt; is a way to share common test setup and teardown between&#xA;multiple test cases, without them calling a setup helper explicitly.&#xA;In most cases, this is better done with a setup helper function as&#xA;described above.&lt;/p&gt;&#xA;&lt;p&gt;There is one case where &lt;code&gt;TestMain&lt;/code&gt; is acceptable, which is the case&#xA;where the test setup is so expensive to run that it will be&#xA;significantly faster to only do it once.&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;&lt;code&gt;t.Run()&lt;/code&gt; is a way of structuring your test output, but it&amp;rsquo;ll&#xA;also make sure that subtests can cancel with &lt;code&gt;t.Fatal()&lt;/code&gt;, without&#xA;affecting the execution of other subtests.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;&lt;code&gt;testing.TB&lt;/code&gt; is an interface for the common methods in&#xA;&lt;code&gt;testing.T&lt;/code&gt; and &lt;code&gt;testing.B&lt;/code&gt;, so it can be used from tests and&#xA;benchmarks alike.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/go-tests/</guid>
      <pubDate>Wed, 10 Feb 2021 22:00:06 +0100</pubDate>
    </item>
    <item>
      <title>Don&#39;t check emptyness before loops</title>
      <link>https://blog.gnoack.org/post/dont-check-emptyness-before-loops</link>
      <description>&lt;p&gt;If your plan is to loop over a collection: You shouldn&amp;rsquo;t check for it being non-empty first.&lt;/p&gt;&#xA;&lt;p&gt;Don&amp;rsquo;t do this:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-java&#34;&gt;if (!stuff.empty()) {&#xA;  for (Item item : stuff) {&#xA;    // ...&#xA;  }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Do this instead:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-java&#34;&gt;for (Item item : stuff) {&#xA;  // ...&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Benefits:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Shorter&lt;/li&gt;&#xA;&lt;li&gt;Less nesting&lt;/li&gt;&#xA;&lt;li&gt;Same performance&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I used to do this too at some point in the past, because I thought&#xA;this would have performance benefits, but in reality, the performance&#xA;benefit is hardly measurable and generally falls into the category&#xA;&lt;a href=&#34;https://wiki.c2.com/?PrematureOptimization&#34;&gt;&amp;ldquo;premature optimization&amp;rdquo;&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Even if there is a little extra code happening between the &lt;code&gt;if&lt;/code&gt; and&#xA;the &lt;code&gt;for&lt;/code&gt;, the performance impact needs to be significant for this to&#xA;make a difference in most cases, and it&amp;rsquo;s probably not worth the&#xA;additional code convolution.&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/dont-check-emptyness-before-loops/</guid>
      <pubDate>Tue, 06 Oct 2020 07:12:04 +0200</pubDate>
    </item>
    <item>
      <title>Go-style coroutines in the FN language</title>
      <link>https://blog.gnoack.org/post/coroutines-in-fn</link>
      <description>&lt;p&gt;My toy Lisp &lt;a href=&#34;https://github.com/gnoack/fn&#34;&gt;fn&lt;/a&gt; is an inherently&#xA;single-threaded language, but with its built-in stack-inspection&#xA;capabilities, it&amp;rsquo;s easy to build coroutines on top.&lt;/p&gt;&#xA;&lt;p&gt;The&#xA;&lt;a href=&#34;https://github.com/gnoack/fn/blob/master/examples/threads.fn#L29&#34;&gt;implementation&lt;/a&gt;&#xA;only has about 20 lines of code, including comments. This article&#xA;contains a simplified implementation in-line. In only rewrote some&#xA;comments to make more sense in context, and removed confusing&#xA;technicalities like &lt;code&gt;fn&lt;/code&gt;&amp;rsquo;s custom method call syntax, the use of&#xA;&lt;code&gt;dynamic-wind&lt;/code&gt; and remarks about tail calls.&lt;/p&gt;&#xA;&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;&#xA;&lt;p&gt;In most programming languages, the call stack is a chain of stack&#xA;frames which ends in the program&amp;rsquo;s entry point.&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;div id=&#39;pikchr-0&#39; class=&#39;pikchr&#39;&gt;&#xA;&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:335px&#39;&gt;&#xA;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 335.463 180.386&#34;&gt;&#xA;&lt;path d=&#34;M129.719,178.226L328.144,178.226L328.144,22.32L129.719,22.32Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M2.16,178.226L58.8529,178.226L58.8529,149.879L2.16,149.879Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;30.5065&#34; y=&#34;164.052&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;bar&lt;/text&gt;&#xA;&lt;polygon points=&#34;30.5065,110.194 34.8265,121.714 26.1865,121.714&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M30.5065,149.879L30.5065,115.954&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;30.5065&#34; y=&#34;120.353&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; font-size=&#34;80%&#34; transform=&#34;rotate(-90 30.5065,130.037)&#34; dominant-baseline=&#34;central&#34;&gt;caller&lt;/text&gt;&#xA;&lt;path d=&#34;M2.16,110.194L58.8529,110.194L58.8529,81.8476L2.16,81.8476Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;30.5065&#34; y=&#34;96.0208&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;foo&lt;/text&gt;&#xA;&lt;polygon points=&#34;30.5065,42.1625 34.8265,53.6825 26.1865,53.6825&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M30.5065,81.8476L30.5065,47.9225&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;30.5065&#34; y=&#34;52.321&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; font-size=&#34;80%&#34; transform=&#34;rotate(-90 30.5065,62.005)&#34; dominant-baseline=&#34;central&#34;&gt;caller&lt;/text&gt;&#xA;&lt;path d=&#34;M2.16,42.1625L58.8529,42.1625L58.8529,13.8161L2.16,13.8161Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;30.5065&#34; y=&#34;27.9893&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;main&lt;/text&gt;&#xA;&lt;path d=&#34;M143.892,107.359L313.971,107.359L313.971,36.4932L143.892,36.4932Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;228.932&#34; y=&#34;51.7663&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;information to&lt;/text&gt;&#xA;&lt;text x=&#34;228.932&#34; y=&#34;71.9263&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;resume execution of&lt;/text&gt;&#xA;&lt;text x=&#34;228.932&#34; y=&#34;92.0863&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;the calling function&lt;/text&gt;&#xA;&lt;path d=&#34;M143.892,164.052L313.971,164.052L313.971,107.359L143.892,107.359Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;228.932&#34; y=&#34;125.626&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;values of local&lt;/text&gt;&#xA;&lt;text x=&#34;228.932&#34; y=&#34;145.786&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;variables and arguments&lt;/text&gt;&#xA;&lt;text x=&#34;228.932&#34; y=&#34;12.24&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;stack frame (simplified)&lt;/text&gt;&#xA;&lt;path d=&#34;M58.8529,178.226L129.719,178.226&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;&#xA;&lt;path d=&#34;M58.8529,149.879L129.719,22.32&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;&#xA;&lt;/svg&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;figcaption&gt;A conventional call stack&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;&#xA;Stack frames are on the heap in fn.&#xA;&lt;/div&gt;&#xA;&lt;p&gt;In the case of C, this call stack is a contiguous memory area, but in&#xA;&lt;em&gt;fn&lt;/em&gt;, the stack frames are actually allocated objects on the heap&#xA;which have pointers to each other. Each stack frame also stores the&#xA;information required to &lt;a href=&#34;https://github.com/gnoack/fn/blob/def2f2164f708df2980364f8f1495e94d0df8690/runtime/interpreter.c#L154&#34;&gt;resume&#xA;it&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;&#xA;Functions can get a handle on their own stack frame&#xA;&lt;/div&gt;&#xA;&lt;p&gt;Additionally, &lt;em&gt;fn&lt;/em&gt; has a natively implemented helper called&#xA;&lt;a href=&#34;https://github.com/gnoack/fn/blob/def2f2164f708df2980364f8f1495e94d0df8690/runtime/primitives.c#L311&#34;&gt;&lt;code&gt;$get-frame&lt;/code&gt;&lt;/a&gt;.&#xA;When called, &lt;code&gt;$get-frame&lt;/code&gt; returns the caller&amp;rsquo;s own stack frame as Lisp&#xA;object which can be manipulated. You can access it from an interactive&#xA;&lt;code&gt;fn&lt;/code&gt; session as well:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-scheme&#34;&gt;fn&amp;gt; ($get-frame)&#xA;#&amp;lt;Frame () @1ff4437b5780&amp;gt;&#xA;fn&amp;gt; (frame-caller ($get-frame))&#xA;#&amp;lt;Frame () @1ff4437b97c4&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2 id=&#34;implementation&#34;&gt;Implementation&lt;/h2&gt;&#xA;&lt;h3 id=&#34;a-queue-of-suspended-coroutines&#34;&gt;A queue of suspended coroutines&lt;/h3&gt;&#xA;&lt;p&gt;For Go-style coroutine behaviour, we keep track of a queue of call&#xA;stacks of currently suspended coroutines. A coroutine which yields&#xA;execution queues itself last, and returns into the first call stack&#xA;from that queue.&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;div id=&#39;pikchr-1&#39; class=&#39;pikchr&#39;&gt;&#xA;&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:422px&#39;&gt;&#xA;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 422.422 210.29&#34;&gt;&#xA;&lt;text x=&#34;39.6576&#34; y=&#34;177.89&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;pop out&lt;/text&gt;&#xA;&lt;text x=&#34;39.6576&#34; y=&#34;198.05&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;(resume)&lt;/text&gt;&#xA;&lt;polygon points=&#34;82.9152,187.97 94.4352,183.65 94.4352,192.29&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M88.6752,187.97L116.931,187.97&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M116.931,202.143L162.285,202.143L162.285,173.797L116.931,173.797Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;polygon points=&#34;139.608,145.45 143.928,156.97 135.288,156.97&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M139.608,173.797L139.608,151.21&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M122.6,145.45L156.616,145.45L156.616,122.773L122.6,122.773Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;polygon points=&#34;139.608,94.4266 143.928,105.947 135.288,105.947&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M139.608,122.773L139.608,100.187&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M122.6,94.4266L156.616,94.4266L156.616,71.7494L122.6,71.7494Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;polygon points=&#34;139.608,43.403 143.928,54.923 135.288,54.923&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M139.608,71.7494L139.608,49.163&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M122.6,43.403L156.616,43.403L156.616,20.7258L122.6,20.7258Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;122.6&#34; y=&#34;73.008&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; transform=&#34;rotate(-90 122.6,83.088)&#34; dominant-baseline=&#34;central&#34;&gt;next to be resumed&lt;/text&gt;&#xA;&lt;path d=&#34;M162.285,202.143L207.64,202.143L207.64,173.797L162.285,173.797Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;polygon points=&#34;184.962,145.45 189.282,156.97 180.642,156.97&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M184.962,173.797L184.962,151.21&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M167.955,145.45L201.97,145.45L201.97,122.773L167.955,122.773Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;polygon points=&#34;184.962,94.4266 189.282,105.947 180.642,105.947&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M184.962,122.773L184.962,100.187&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M167.955,94.4266L201.97,94.4266L201.97,71.7494L167.955,71.7494Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M207.64,202.143L252.994,202.143L252.994,173.797L207.64,173.797Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;polygon points=&#34;230.317,145.45 234.637,156.97 225.997,156.97&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M230.317,173.797L230.317,151.21&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M213.309,145.45L247.325,145.45L247.325,122.773L213.309,122.773Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;polygon points=&#34;230.317,94.4266 234.637,105.947 225.997,105.947&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M230.317,122.773L230.317,100.187&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M213.309,94.4266L247.325,94.4266L247.325,71.7494L213.309,71.7494Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;polygon points=&#34;230.317,43.403 234.637,54.923 225.997,54.923&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M230.317,71.7494L230.317,49.163&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M213.309,43.403L247.325,43.403L247.325,20.7258L213.309,20.7258Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M252.994,202.143L298.348,202.143L298.348,173.797L252.994,173.797Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;polygon points=&#34;275.671,145.45 279.991,156.97 271.351,156.97&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M275.671,173.797L275.671,151.21&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M258.663,145.45L292.679,145.45L292.679,122.773L258.663,122.773Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;polygon points=&#34;275.671,94.4266 279.991,105.947 271.351,105.947&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M275.671,122.773L275.671,100.187&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M258.663,94.4266L292.679,94.4266L292.679,71.7494L258.663,71.7494Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;polygon points=&#34;298.348,187.97 309.868,183.65 309.868,192.29&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M304.108,187.97L332.364,187.97&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;379.193&#34; y=&#34;177.89&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;push in&lt;/text&gt;&#xA;&lt;text x=&#34;379.193&#34; y=&#34;198.05&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;(suspend)&lt;/text&gt;&#xA;&lt;/svg&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;figcaption&gt;A queue of suspended call stacks&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;&#xA;Starting new coroutines&#xA;&lt;/div&gt;&#xA;&lt;p&gt;A new coroutine is started with &lt;code&gt;thread-new!&lt;/code&gt;. &lt;code&gt;thread-new!&lt;/code&gt; suspends&#xA;its caller and itself becomes the entry point for the new coroutine&#xA;which immediately executes. The helper function &lt;code&gt;thread-die!&lt;/code&gt;&#xA;unschedules the current thread from execution by scheduling another&#xA;coroutine without adding itself back to the queue.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-scheme&#34;&gt;(defn thread-new! (thunk)&#xA;  ;; Suspend current call stack.&#xA;  (queue-push! *thread-queue* (frame-caller ($get-frame)))&#xA;  ;; Make sure we don&#39;t accidentally&#xA;  (set-frame-caller! ($get-frame) &#39;*should-never-be-used*)&#xA;  ;; Call thunk, then call thread-die!.&#xA;  (thunk)&#xA;  (thread-die!))&#xA;&#xA;(defn thread-die! ()&#xA;  (set-frame-caller! ($get-frame)&#xA;                     (queue-pop! *thread-queue*))&#xA;  nil)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h3 id=&#34;switching-between-coroutines&#34;&gt;Switching between coroutines&lt;/h3&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;&#xA;In some languages, &lt;tt&gt;next-thread!&lt;/tt&gt; would be called &lt;tt&gt;yield&lt;/tt&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;To switch between coroutines, all you need to do is to have &lt;em&gt;multiple&#xA;call stacks&lt;/em&gt; and switch between them. In &lt;em&gt;fn&lt;/em&gt;, this is done in the&#xA;&lt;code&gt;next-thread!&lt;/code&gt; function. &lt;code&gt;next-thread!&lt;/code&gt;, when called, will swizzle out&#xA;the calling stack frame stored in its own stack frame. That way, the&#xA;function can return into a different call stack than the one it was&#xA;invoked from.&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;div id=&#39;pikchr-2&#39; class=&#39;pikchr&#39;&gt;&#xA;&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:185px&#39;&gt;&#xA;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 185.737 219.753&#34;&gt;&#xA;&lt;path d=&#34;M24.8372,217.593L115.546,217.593L115.546,189.247L24.8372,189.247Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;70.1915&#34; y=&#34;203.42&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;next-thread!&lt;/text&gt;&#xA;&lt;polygon points=&#34;30.5065,143.892 34.8265,155.412 26.1865,155.412&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M58.8529,189.247 L 44.6797,180.743 Q 30.5065,172.239 30.5065,160.946 L 30.5065,149.652&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M2.16,143.892L58.8529,143.892L58.8529,115.546L2.16,115.546Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;polygon points=&#34;30.5065,87.1994 34.8265,98.7194 26.1865,98.7194&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M30.5065,115.546L30.5065,92.9594&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M2.16,87.1994L58.8529,87.1994L58.8529,58.8529L2.16,58.8529Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;polygon points=&#34;30.5065,30.5065 34.8265,42.0265 26.1865,42.0265&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M30.5065,58.8529L30.5065,36.2665&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M2.16,30.5065L58.8529,30.5065L58.8529,2.16L2.16,2.16Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M16.3332,166.569L56.0183,166.569&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(255,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M16.3332,177.908L56.0183,155.231&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(255,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;56.0183&#34; y=&#34;155.231&#34; text-anchor=&#34;start&#34; fill=&#34;rgb(255,0,0)&#34; dominant-baseline=&#34;central&#34;&gt; 1.&lt;/text&gt;&#xA;&lt;polygon points=&#34;155.231,143.892 159.551,155.412 150.911,155.412&#34; style=&#34;fill:rgb(60,179,113)&#34;/&gt;&#xA;&lt;path d=&#34;M92.8687,189.247 L 124.05,177.908 Q 155.231,166.569 155.231,158.111 L 155.231,149.652&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(60,179,113);stroke-dasharray:7.2,7.2;&#34; /&gt;&#xA;&lt;text x=&#34;124.05&#34; y=&#34;154.869&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(60,179,113)&#34; dominant-baseline=&#34;central&#34;&gt;2.&lt;/text&gt;&#xA;&lt;path d=&#34;M126.884,143.892L183.577,143.892L183.577,115.546L126.884,115.546Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;polygon points=&#34;155.231,87.1994 159.551,98.7194 150.911,98.7194&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M155.231,115.546L155.231,92.9594&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M126.884,87.1994L183.577,87.1994L183.577,58.8529L126.884,58.8529Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;polygon points=&#34;155.231,30.5065 159.551,42.0265 150.911,42.0265&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M155.231,58.8529L155.231,36.2665&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M126.884,30.5065L183.577,30.5065L183.577,2.16L126.884,2.16Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;/svg&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;figcaption&gt;next-thread! returns into a different call stack than it was called from&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;&lt;code&gt;next-thread!&lt;/code&gt; is implemented as follows:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-scheme&#34;&gt;(defn next-thread! ()&#xA;  ;; Push our own frame&#39;s caller onto the queue.&#xA;  (queue-push! *thread-queue* (frame-caller ($get-frame)))&#xA;  ;; Remove a suspended stack frame from the queue,&#xA;  ;; and set it as our own caller, so we&#39;ll return to it.&#xA;  (set-frame-caller! ($get-frame)&#xA;                     (queue-pop! *thread-queue*))&#xA;  nil)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h3 id=&#34;caveats-about-tail-calls&#34;&gt;Caveats about tail calls&lt;/h3&gt;&#xA;&lt;p&gt;Manipulating your own stack frame leads to a simple and short&#xA;implementation, but the devil is in the details.&lt;/p&gt;&#xA;&lt;p&gt;In particular, in languages with implicit and automatic tail calls, an&#xA;invocation such as &lt;code&gt;(set-frame-caller! ($get-frame) ...)&lt;/code&gt; cannot be&#xA;put at the end of a function, of you would manipulate the caller of a&#xA;function that won&amp;rsquo;t ever return again. To work around this problem,&#xA;functions like &lt;code&gt;next-thread!&lt;/code&gt; and &lt;code&gt;thread-die!&lt;/code&gt; return &lt;code&gt;nil&lt;/code&gt;&#xA;explicitly at the end, so that &lt;code&gt;set-frame-caller!&lt;/code&gt; does not get&#xA;invoked with a tail call.&lt;/p&gt;&#xA;&lt;p&gt;The full coroutine implementation is in the &lt;code&gt;fn&lt;/code&gt; repository in&#xA;&lt;a href=&#34;https://github.com/gnoack/fn/blob/master/examples/threads.fn&#34;&gt;&lt;code&gt;examples/threads.fn&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/coroutines-in-fn/</guid>
      <pubDate>Mon, 14 Sep 2020 11:15:00 +0100</pubDate>
    </item>
    <item>
      <title>Rendering drawings with tuhirender</title>
      <link>https://blog.gnoack.org/post/tuhirender</link>
      <description>&lt;p&gt;Recently, almost all my digital drawings were made with a &lt;a href=&#34;https://www.amazon.de/Wacom-Bamboo-Slate-Smartpad-Digitalisierungs-Funktion/dp/B01L1V61MC&#34;&gt;Bamboo&#xA;Slate&lt;/a&gt;&#xA;tablet and &lt;a href=&#34;https://github.com/tuhiproject/tuhi&#34;&gt;Tuhi&lt;/a&gt;. It was good&#xA;fun to take Tuhi&amp;rsquo;s drawing data and create my own renderer&#xA;&lt;a href=&#34;https://github.com/gnoack/tuhirender&#34;&gt;tuhirender&lt;/a&gt;, which can be used&#xA;from the command line to produce some more advanced effects and tune&#xA;more of the rendering knobs.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;tuhirender&lt;/code&gt; replaces Tuhi&amp;rsquo;s own renderer by building on Tuhi&amp;rsquo;s&#xA;JSON-based output format for line coordinates and pen pressure data.&lt;/p&gt;&#xA;&lt;h2 id=&#34;basic-invocation&#34;&gt;Basic invocation&lt;/h2&gt;&#xA;&lt;p&gt;The basic invocation is:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;tuhirender -width 200 -fit -o out.png &amp;lt; in/1593622352.json&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;All parameters are in principle optional, but this invocation shows&#xA;the most commonly used options. &lt;code&gt;-width&lt;/code&gt; specifies the desired output&#xA;width in pixels.&lt;/p&gt;&#xA;&lt;h2 id=&#34;animate-a-drawing&#34;&gt;Animate a drawing&lt;/h2&gt;&#xA;&lt;p&gt;To animate the drawing progress, use the &lt;code&gt;gif&lt;/code&gt; output format by passing the flag &lt;code&gt;--format gif&lt;/code&gt; and specifying a matching filename with &lt;code&gt;-o out.gif&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/images/drawing.gif&#34; alt=&#34;&#34;&gt;&#xA;&lt;figcaption&gt;&lt;p&gt;An animated drawing&lt;/p&gt;&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;h2 id=&#34;simplify-line-segments&#34;&gt;Simplify line segments.&lt;/h2&gt;&#xA;&lt;p&gt;With the &lt;code&gt;--simplify&lt;/code&gt; flag, &lt;code&gt;tuhirender&lt;/code&gt; simplifies all lines. See my&#xA;previuos post on the topic: &lt;a href=&#34;https://blog.gnoack.org/post/path-simplification-lib/&#34;&gt;Go: Path simplification&#xA;library&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/images/hippie.png&#34; alt=&#34;An original and a path-simplified picture side-by-side&#34;&gt;&#xA;&lt;figcaption&gt;&lt;p&gt;Original and simplified version side-by-side&lt;/p&gt;&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;This picture is a bit of an extreme example to demonstrate the&#xA;simplification. When tweaking the parameters a bit, the simplification&#xA;is less visible. At some point, I might be able to use this for&#xA;outputting vector graphics at reduced file size and acceptable quality&#xA;loss.&lt;/p&gt;&#xA;&lt;h2 id=&#34;some-sample-pictures&#34;&gt;Some sample pictures&lt;/h2&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/images/winged-victory-of-samothrace.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;figcaption&gt;&lt;p&gt;A bigger picture: Winged Victory of Samothrace&lt;/p&gt;&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;This is the biggest picture I&amp;rsquo;ve drawn so far with the tablet; I&amp;rsquo;m&#xA;happy with how it turned out. The hatching renders nicely and produces&#xA;the desired shades.&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/images/sausage.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;figcaption&gt;&lt;p&gt;A cartoon drawing: A man, a dog and a sausage&lt;/p&gt;&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;This cartoon drawing is simpler and has a bigger zoom, so it&amp;rsquo;s easier&#xA;to see how the change in pen pressure is rendered.&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/images/gopher.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;figcaption&gt;&lt;p&gt;A gopher&lt;/p&gt;&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;The gopher picture has a lot of nuanced Pen pressure, and arguably it&#xA;looked slightly better on paper. At the moment, &lt;code&gt;tuhirender&lt;/code&gt; renders&#xA;pen pressure by modifying the line width on the go. I suspect that&#xA;changing the line opacity might be better, but I&amp;rsquo;m still looking for&#xA;an elegant algorithm to fix up the artifacts between line segments&#xA;when doing that.&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/tuhirender/</guid>
      <pubDate>Mon, 06 Jul 2020 00:04:10 +0200</pubDate>
    </item>
    <item>
      <title>Go: Test Cleanup in Go 1.14</title>
      <link>https://blog.gnoack.org/post/go-testing-cleanup</link>
      <description>&lt;p&gt;In Go 1.14, the new &lt;a href=&#34;https://godoc.org/testing#T.Cleanup&#34;&gt;T.Cleanup()&lt;/a&gt;&#xA;function schedules defer-like work to be done after the current test.&#xA;This makes it possible to write very comfortable setup helper&#xA;functions:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-golang&#34;&gt;func SetUpFrobnicator(t *testing.T) *frob.Frobnicator {&#xA;    t.Helper()&#xA;&#xA;    f := frob.New()    // Do setup.&#xA;    t.Cleanup(f.Close) // Schedule cleanup for later.&#xA;    return f&#xA;}&#xA;&#xA;func TestFoobar(t *testing.T) {&#xA;    f := SetUpFrobnicator(t)&#xA;&#xA;    // (Run the test itself, using f.)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Previously, presumably the most idiomatic thing would have been to&#xA;return a &amp;ldquo;cancel&amp;rdquo; callback from the helper function and rely on the&#xA;test to defer it.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;m almost a bit surprised that the Go test framework offers this&#xA;now - otherwise, compared to other languages, Go&amp;rsquo;s test code is very&#xA;similar in style to production code (e.g. it doesn&amp;rsquo;t even have assert&#xA;functions).&lt;/p&gt;&#xA;&lt;p&gt;Related articles on this blog:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/post/setup-cleanup/&#34;&gt;The Setup-Cleanup problem&lt;/a&gt; in different programming languages&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/post/base_fixture/&#34;&gt;Shared Base Fixture&lt;/a&gt; in unit tests&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/go-testing-cleanup/</guid>
      <pubDate>Thu, 14 May 2020 09:26:41 +0200</pubDate>
    </item>
    <item>
      <title>Why Software Design?</title>
      <link>https://blog.gnoack.org/post/why-software-design</link>
      <description>&lt;p&gt;The main technique in software design is this: You look at the&#xA;entirety of your system and you decompose it into pieces that are more&#xA;manageable and have clear interfaces. This approach is usually&#xA;referred to as &lt;em&gt;modularization&lt;/em&gt;.&lt;/p&gt;&#xA;&lt;p&gt;But what&amp;rsquo;s the point of investing such an effort if in the end only&#xA;the externally visible properties of a software matter?&lt;/p&gt;&#xA;&lt;p&gt;In his classic paper “On the Criteria To Be Used in Decomposing&#xA;Systems into Modules”&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, David Parnas gives the following&#xA;rationale:&lt;/p&gt;&#xA;&lt;figure class=&#34;alignright&#34;&gt;&#xA;&lt;img src=&#34;/images/parnas.png&#34; alt=&#34;David Parnas&#34;/&gt;&#xA;&lt;figcaption&gt;David Parnas&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;The benefits expected of modular&#xA;programming are (1) &lt;em&gt;managerial&lt;/em&gt; &amp;ndash; development time should be&#xA;shortened because separate groups would work on each module with&#xA;little need for communication; (2) &lt;em&gt;product flexibility&lt;/em&gt; &amp;ndash; it&#xA;should be possible to make drastic changes to one module without a&#xA;need to change others; (3) &lt;em&gt;comprehensibility&lt;/em&gt; &amp;ndash; it should be&#xA;possible to study the system one module at a time. The whole system&#xA;can therefore be better designed because it is better understood.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;To paraphrase this in today&amp;rsquo;s terminology, the benefits of modularization are:&lt;/p&gt;&#xA;&lt;p&gt;(1) &lt;strong&gt;To enable independent work&lt;/strong&gt; on different modules through clear&#xA;interfaces which reduce communication overhead.&lt;/p&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;Conway&#39;s Law&lt;/div&gt;&#xA;&lt;p&gt;A more sarcastic take on cross-team communication overhead is&#xA;&lt;a href=&#34;https://en.wikipedia.org/wiki/Conway%27s_law&#34;&gt;Conway&amp;rsquo;s Law&lt;/a&gt;, which&#xA;states that any system designed by an organization will reflect that&#xA;organization&amp;rsquo;s communication structure.&lt;/p&gt;&#xA;&lt;p&gt;(2) &lt;strong&gt;To simplify future changes&lt;/strong&gt;, by aligning the code so that anticipated&#xA;changes are easy.&lt;/p&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;Need to anticipate changing requirements!&lt;/div&gt;&#xA;&lt;p&gt;Changes are easy when they are contained within a module or crossing&#xA;few module boundaries. The difficulty is to &lt;em&gt;identify&lt;/em&gt; likely future&#xA;changes and lay out the system accordingly, so that they will be a fit&#xA;with the design and won&amp;rsquo;t require changes to the bigger architecture.&lt;/p&gt;&#xA;&lt;p&gt;As David Parnas says himself in the conclusion to his paper:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;We propose instead that one begins with a list of difficult design&#xA;decisions or design decisions which are likely to change. Each&#xA;module is then designed to hide such a decision from the others.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Modules should not rely on each other beyond what their interfaces&#xA;guarantee, so that if you change a module, the change is contained&#xA;behind its interface and not observable to others.&lt;/p&gt;&#xA;&lt;p&gt;(3) &lt;strong&gt;To increase confidence in functionality&lt;/strong&gt;, by making reasoning&#xA;about relevant aspects easier.&lt;/p&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;Easier reasoning for module users&lt;/div&gt;&#xA;&lt;p&gt;The key here is that the interface to each module should give a more&#xA;abstract guarantee which hides the module&amp;rsquo;s implementation details. If&#xA;the right abstraction is picked, the module&amp;rsquo;s users will be able to&#xA;reason about it in simpler terms and avoid dealing with details.&lt;/p&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;Deep classes&lt;/div&gt;&#xA;&lt;p&gt;In a good modularization, the interface definition is small and the&#xA;contained functionality is large (a property which John Ousterhout&#xA;calls &amp;ldquo;Deep Classes&amp;rdquo;)&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. This minimizes the effort to use a&#xA;module and maximizes its benefit.&lt;/p&gt;&#xA;&lt;p&gt;Besides reasoning about behavior, a good system decomposition can&#xA;also help reasoning about other aspects. For example, it&amp;rsquo;s easier to&#xA;reason about crash resilience if different parts of the system are&#xA;deployed as separate services.&lt;/p&gt;&#xA;&lt;div class=&#34;sidenote&#34;&gt;Easier reasoning within modules&lt;/div&gt;&#xA;&lt;p&gt;Finally, a suitable system decomposition also simplifies reasoning&#xA;&lt;em&gt;within&lt;/em&gt; a module, which now has a clear contract to fulfill, as&#xA;defined by the module&amp;rsquo;s interface.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;There is more to be said&lt;/strong&gt; about modularization techniques and&#xA;different approaches on how to deal with the uncertainties of changing&#xA;requirements, but that has to go on a follow-up article. Subscribe to&#xA;this blog with your RSS reader to get notified of future articles.&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;David Parnas, &lt;a href=&#34;https://www.win.tue.nl/~wstomv/edu/2ip30/references/criteria_for_modularization.pdf&#34;&gt;On the Criteria To Be Used in Decomposing&#xA;Systems into Modules&lt;/a&gt; (1972)&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;John Ousterhout, &lt;a href=&#34;https://www.amazon.com/Philosophy-Software-Design-John-Ousterhout/dp/1732102201&#34;&gt;A Philosophy of Software&#xA;Design&lt;/a&gt; (2018)&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/why-software-design/</guid>
      <pubDate>Wed, 13 May 2020 21:10:10 +0200</pubDate>
    </item>
    <item>
      <title>Go: Sharing templates across multiple pages</title>
      <link>https://blog.gnoack.org/post/go_templates</link>
      <description>&lt;figure&gt;&#xA;&lt;img src=&#34;/images/gutengopher.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;figcaption&gt;&lt;p&gt;Renaissance gopher Johannes Gopherberg after inventing html/template&lt;/p&gt;&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;I&amp;rsquo;m using &lt;code&gt;html/template&lt;/code&gt; much too seldom to remember how to&#xA;properly share common template blocks across multiple pages. Today I&#xA;had to figure it out for the second time. It&amp;rsquo;s about time to document&#xA;it!&lt;/p&gt;&#xA;&lt;p&gt;The approach presented here both (1) makes it possible to share&#xA;template blocks across multiple logical pages, and (2) makes it easy&#xA;to use them using &lt;code&gt;tmpl.Execute(writer, data)&lt;/code&gt; in your HTTP handlers.&lt;/p&gt;&#xA;&lt;p&gt;In particular, with this approach, all pages share a common top-level&#xA;definition of an HTML page, as opposed to maintaining separate header&#xA;and footer templates whose opening and closing tags would need to be&#xA;kept in sync.&lt;/p&gt;&#xA;&lt;p&gt;From the &lt;a href=&#34;https://golang.org/pkg/text/template/#Template.Clone&#34;&gt;text/template documentation&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Clone can be used to prepare common templates and use them with&#xA;variant definitions for other templates by adding the variants after&#xA;the clone is made.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;With &lt;code&gt;Clone()&lt;/code&gt;, you can have a separate &lt;code&gt;template.Template&lt;/code&gt; instance&#xA;for each of your pages, while making them share a common set of base&#xA;templates at the same time.&lt;/p&gt;&#xA;&lt;p&gt;The way you&amp;rsquo;d like to construct these goes something like this:&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/images/templates.svg&#34; alt=&#34;&#34;&gt;&#xA;&lt;figcaption&gt;&lt;p&gt;Constructing separate template collections from a shared base&lt;/p&gt;&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;None of this is really a secret. However, before &lt;code&gt;.Clone()&lt;/code&gt; existed,&#xA;it wasn&amp;rsquo;t as easy, and it&amp;rsquo;s still easy to find a lot of outdated&#xA;advice.&lt;/p&gt;&#xA;&lt;h2 id=&#34;example&#34;&gt;Example&lt;/h2&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s go step by step.&lt;/p&gt;&#xA;&lt;h3 id=&#34;directory-structure-for-this-example&#34;&gt;Directory structure for this example&lt;/h3&gt;&#xA;&lt;p&gt;The &lt;em&gt;base templates&lt;/em&gt; live in &lt;code&gt;templates/base/*.html&lt;/code&gt;. These include&#xA;&lt;code&gt;page.html&lt;/code&gt; for the top-level definition of an HTML file, a dummy&#xA;definition for the main page content in &lt;code&gt;main.html&lt;/code&gt;, as well as&#xA;various helpers that may be reused across various pages.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;em&gt;per-page templates&lt;/em&gt; live in &lt;code&gt;templates/${PAGENAME}/*.html&lt;/code&gt;. A&#xA;minimal page just redefines &lt;code&gt;main.html&lt;/code&gt; to have the necessary content.&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/images/template_instantiation.svg&#34; alt=&#34;&#34;&gt;&#xA;&lt;figcaption&gt;&lt;p&gt;The templates in foo/ override main.html from base/.&lt;/p&gt;&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;h3 id=&#34;create-the-base-templates&#34;&gt;Create the base templates&lt;/h3&gt;&#xA;&lt;p&gt;First, define the base templates with the &lt;code&gt;page.html&lt;/code&gt; definition as&#xA;root template for all template instantiations.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;base := template.New(&amp;quot;page.html&amp;quot;)&#xA;base  = template.Must(&#xA;    base.ParseGlob(&amp;quot;templates/base/*.html&amp;quot;)))&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;We name the template collection &lt;code&gt;page.html&lt;/code&gt;, so that &lt;code&gt;page.html&lt;/code&gt; will&#xA;be used as the default template to render for all of our pages, when&#xA;it gets called through &lt;code&gt;.Execute()&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;templates/base/page.html&lt;/code&gt; template defines the top-level HTML structure with&#xA;navigation bars and core site elements, and includes the main page&#xA;content &lt;code&gt;main.html&lt;/code&gt; with a &lt;code&gt;block&lt;/code&gt; action:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;html&amp;gt;&#xA;&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;...&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&#xA;&amp;lt;body&amp;gt;&#xA;  &amp;lt;!-- navigation, main site elements, etc --&amp;gt;&#xA;  {{- block &amp;quot;main.html&amp;quot; . -}}{{- end -}}&#xA;&amp;lt;/body&amp;gt;&#xA;&amp;lt;/html&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h3 id=&#34;derive-the-specialized-templates-for-the-foo-handler&#34;&gt;Derive the specialized templates for the &lt;code&gt;foo&lt;/code&gt; handler&lt;/h3&gt;&#xA;&lt;p&gt;In the package or file for the &lt;code&gt;foo&lt;/code&gt; handler, create a local &lt;code&gt;var fooTmpl *template.Template&lt;/code&gt; where you derive the base template:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;fooTmpl := template.Must(baseTmpl.Clone())&#xA;fooTmpl  = template.Must(&#xA;    fooTmpl.ParseGlob(&amp;quot;templates/foo/*.html&amp;quot;))&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;We define page content in the &lt;code&gt;templates/foo/main.html&lt;/code&gt; template:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;h1&amp;gt;Hello, world!&amp;lt;/h1&amp;gt;&#xA;&amp;lt;p&amp;gt;This is an example template.&amp;lt;/p&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h3 id=&#34;use-the-specialized-templates-in-your-handler&#34;&gt;Use the specialized templates in your handler&lt;/h3&gt;&#xA;&lt;p&gt;Finally, all that&amp;rsquo;s needed to use the specialized templates in a&#xA;handler is to just call &lt;code&gt;.Execute()&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;func handleFoo(w http.ResponseWriter, req *http.Request) {&#xA;        data := fooData{Key: &amp;quot;Value&amp;quot;}&#xA;        fooTmpl.Execute(w, data)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;It will automatically instantiate the collection of templates starting&#xA;from &lt;code&gt;page.html&lt;/code&gt;.&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/go_templates/</guid>
      <pubDate>Sun, 03 May 2020 11:10:01 +0100</pubDate>
    </item>
    <item>
      <title>Go: Path simplification library</title>
      <link>https://blog.gnoack.org/post/path-simplification-lib</link>
      <description>&lt;p&gt;A few weeks ago, I got myself a &lt;a href=&#34;https://www.amazon.de/Wacom-Bamboo-Slate-Smartpad-Digitalisierungs-Funktion/dp/B01L1V61MC&#34;&gt;Bamboo&#xA;Slate&lt;/a&gt;&#xA;tablet, and had a lot of fun playing around with the output. The Linux&#xA;software for talking to that device is&#xA;&lt;a href=&#34;https://github.com/tuhiproject/tuhi&#34;&gt;Tuhi&lt;/a&gt;, which is GUI driven, but&#xA;also dumps the raw point and pressure data in JSON format into a&#xA;directory.&lt;/p&gt;&#xA;&lt;p&gt;As a side effect of playing around with that, I published a &lt;a href=&#34;https://github.com/gnoack/path&#34;&gt;2d path&#xA;simplification library&lt;/a&gt; which uses the&#xA;&lt;a href=&#34;https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm&#34;&gt;Ramer-Douglas-Peucker&#xA;algorithm&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Given a sequence of 2D points, the algorithm determines a subset of&#xA;these points so that the path drawn by these is still reasonably close&#xA;to the original. Here is an example output:&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/images/hippie.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;figcaption&gt;&lt;p&gt;Original and simplified version side-by-side&lt;/p&gt;&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;I found the Ramer-Douglas-Peucker algorithm to be very clever, my&#xA;attempts to come up with my own algorithm had terrible results in&#xA;comparison.&lt;/p&gt;&#xA;&lt;p&gt;The library is here:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Source: &lt;a href=&#34;https://github.com/gnoack/path&#34;&gt;https://github.com/gnoack/path&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;Godoc: &lt;a href=&#34;https://godoc.org/github.com/gnoack/path&#34;&gt;https://godoc.org/github.com/gnoack/path&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I have a vague idea to use this for simplifying diagram drawings and&#xA;straightening out imprecisely drawn shapes, replacing squiggly boxes&#xA;and arrows with properly aligned ones. I&amp;rsquo;m not sure whether I&amp;rsquo;m going&#xA;in the right direction with this approach, given that I&amp;rsquo;m not making&#xA;use of pressure data and my knowledge of the shapes I want to&#xA;recognize; we&amp;rsquo;ll see whether it&amp;rsquo;ll turn out to work.&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/path-simplification-lib/</guid>
      <pubDate>Sun, 05 Apr 2020 14:13:52 +0200</pubDate>
    </item>
    <item>
      <title>Go: The lack of generics</title>
      <link>https://blog.gnoack.org/post/go-lack-of-generics</link>
      <description>&lt;p&gt;Go&amp;rsquo;s lack of generics means that people can&amp;rsquo;t overengineer in the way&#xA;they are used to, so they need to put more thought into their designs.&lt;/p&gt;&#xA;&lt;p&gt;There are some use cases where abstractions with generics are better&#xA;to the current ones (e.g. the &lt;code&gt;sort&lt;/code&gt; package), but by and large, in&#xA;other languages, people use them to build towers of abstractions which&#xA;you&amp;rsquo;ll later need to wrap your head around, which introduce conceptual&#xA;duplication (e.g. mocking and predicate frameworks) and which lead to&#xA;a fragmentation of Go style (as would be the case if people start&#xA;building abstractions to hide the &lt;code&gt;go&lt;/code&gt; keyword, like threading and&#xA;future libraries).&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/go-lack-of-generics/</guid>
      <pubDate>Sun, 05 Apr 2020 11:53:00 +0200</pubDate>
    </item>
    <item>
      <title>The Setup-Cleanup problem</title>
      <link>https://blog.gnoack.org/post/setup-cleanup</link>
      <description>&lt;figure&gt;&#xA;&lt;img src=&#34;/images/cleanup.png&#34; alt=&#34;A picture of the Sorcerer&amp;rsquo;s apprentice enchanting brooms to fetch water&#34;&gt;&#xA;&lt;figcaption&gt;&lt;p&gt;A fully automated cleanup strategy.&lt;/p&gt;&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;This is a comparison of different programming idioms for performing&#xA;cleanup work.&lt;/p&gt;&#xA;&lt;p&gt;Common use cases where this is used include:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Locking and unlocking synchronization locks.&lt;/li&gt;&#xA;&lt;li&gt;Opening and closing files.&lt;/li&gt;&#xA;&lt;li&gt;Canceling asynchronous operations that aren&amp;rsquo;t needed any more.&lt;/li&gt;&#xA;&lt;li&gt;Allocation and deallocation.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;a-naive-solution-cluttered-cleanups&#34;&gt;A naive solution: Cluttered cleanups&lt;/h2&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-c&#34;&gt;int frobnicate() {&#xA;        set_up();&#xA;&#xA;        int err = foo();&#xA;        if (err) {&#xA;                clean_up();  // &amp;lt;-- 1.&#xA;                return err;&#xA;        }&#xA;&#xA;        if (!bar()) {&#xA;                clean_up();  // &amp;lt;-- 2.&#xA;                return ERROR_ACCESS;&#xA;        }&#xA;&#xA;        baz();&#xA;&#xA;        clean_up();          // &amp;lt;-- 3.&#xA;        return SUCCESS;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;There are now three places where &lt;code&gt;clean_up()&lt;/code&gt; is being called (Code&#xA;duplication), and they are all far away from the call to &lt;code&gt;set_up()&lt;/code&gt;.&#xA;When the code changes a bit, it&amp;rsquo;s easy to miss one and introduce&#xA;cleanup issues. This is not a well-maintainable approach.&lt;/p&gt;&#xA;&lt;h2 id=&#34;linux-kernel-style-c&#34;&gt;Linux kernel style (C)&lt;/h2&gt;&#xA;&lt;p&gt;The Linux kernel uses gotos to coordinate a function&amp;rsquo;s cleanup:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-c&#34;&gt;int frobnicate()&#xA;{&#xA;        int rc = 0;&#xA;&#xA;        set_up();&#xA;&#xA;        rc = foo();&#xA;        if (rc)&#xA;                goto out;&#xA;&#xA;        if (!bar()) {&#xA;                rc = EACCES;&#xA;                goto out;&#xA;        }&#xA;&#xA;        baz();&#xA;&#xA;out:&#xA;        clean_up();  // &amp;lt;--&#xA;        return rc;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;All function exits happening after &lt;code&gt;set_up()&lt;/code&gt; need to jump to the&#xA;label where the &lt;code&gt;clean_up()&lt;/code&gt; is done.&lt;/p&gt;&#xA;&lt;p&gt;Note that this pattern can be nested: With multiple independent setup&#xA;and cleanup steps, the function ends with a sequence of multiple&#xA;cleanup operations and multiple exit labels&#xA;(&lt;a href=&#34;https://github.com/torvalds/linux/blob/v5.4/fs/afs/rxrpc.c#L362&#34;&gt;example&lt;/a&gt;).&lt;/p&gt;&#xA;&lt;p&gt;A longer explanation is at &lt;a href=&#34;https://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c&#34;&gt;Eli Bendersky&amp;rsquo;s&#xA;website&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;resource-acquisition-is-initialization-c&#34;&gt;Resource Acquisition is Initialization (C++)&lt;/h2&gt;&#xA;&lt;p&gt;In C++, setup and cleanup is frequently bound to object lifetimes,&#xA;which are deterministic there. This is an example using&#xA;&lt;a href=&#34;https://abseil.io&#34;&gt;Abseil&amp;rsquo;s&lt;/a&gt;&#xA;&lt;a href=&#34;https://abseil.io/docs/cpp/guides/synchronization#the-mutexlock-wrapper&#34;&gt;&lt;code&gt;absl::MutexLock&lt;/code&gt;&lt;/a&gt;&#xA;class:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-c++&#34;&gt;void MyClass::Frobnicate() {&#xA;  absl::MutexLock l(&amp;amp;mutex_);&#xA;&#xA;  Foo();  // under lock&#xA;  Bar();  // under lock&#xA;  Baz();  // under lock&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The lifetime of the &lt;code&gt;l&lt;/code&gt; variable ends with the function scope, and&#xA;&lt;code&gt;absl::MutexLock&lt;/code&gt;&amp;rsquo;s constructor and destructor are locking and&#xA;unlocking the mutex.&lt;/p&gt;&#xA;&lt;p&gt;This pattern can also be nested. C++ guarantees that variable&#xA;destruction happens in the inverse order of construction.&lt;/p&gt;&#xA;&lt;p&gt;The RAII pattern&#xA;(&lt;a href=&#34;https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization&#34;&gt;Wikipedia&lt;/a&gt;)&#xA;is also used in other languages like Rust (&lt;a href=&#34;https://doc.rust-lang.org/std/ops/trait.Drop.html&#34;&gt;&lt;code&gt;Drop&lt;/code&gt;&#xA;trait&lt;/a&gt;).&lt;/p&gt;&#xA;&lt;p&gt;To a similar extent, similar functionality to RAII is also available&#xA;in C, when using the GCC-specific&#xA;&lt;a href=&#34;https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-cleanup-variable-attribute&#34;&gt;&lt;code&gt;__attribute__((__cleanup__(f)))&lt;/code&gt;&lt;/a&gt;&#xA;language extension. This extension lets you attach a cleanup function&#xA;to a variable scope, but the cleanup is defined in the place where the&#xA;variable is defined, not in the type.&lt;/p&gt;&#xA;&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;As readers pointed out, a newer variant of C#&amp;rsquo;s &lt;code&gt;using&lt;/code&gt; statement&#xA;implements a similar non-nested cleanup bound to variable lifetime as&#xA;well. See &lt;a href=&#34;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement&#34;&gt;the&#xA;documentation&lt;/a&gt;&#xA;comment by Morgens Heller Gabe below for examples.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h2 id=&#34;defer-statement-go&#34;&gt;&amp;ldquo;Defer&amp;rdquo; statement (Go)&lt;/h2&gt;&#xA;&lt;p&gt;Go has a language feature for cleanup:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;func (m *MyClass) Frobnicate() {&#xA;  m.mu_.Lock()&#xA;  defer m.mu_.Unlock()&#xA;&#xA;  Foo()  // under lock&#xA;  Bar()  // under lock&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The &lt;code&gt;defer&lt;/code&gt; statement defers a function call until the current&#xA;function exits.&lt;/p&gt;&#xA;&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;The Zig language has syntactically similar&#xA;&lt;a href=&#34;https://ziglang.org/documentation/master/#defer&#34;&gt;&lt;code&gt;defer&lt;/code&gt;&lt;/a&gt; and&#xA;&lt;a href=&#34;https://ziglang.org/documentation/master/#errdefer&#34;&gt;&lt;code&gt;errdefer&lt;/code&gt;&lt;/a&gt;&#xA;statements. Other than in Go, Zig executes the cleanup when leaving&#xA;the current scope rather than when leaving the function.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h2 id=&#34;with-blocks-and-friends-python-c-java&#34;&gt;&amp;ldquo;With&amp;rdquo; blocks and friends (Python, C#, Java)&lt;/h2&gt;&#xA;&lt;p&gt;Python implements a syntax which makes it easy to acquire resources&#xA;during the execution of a nested block of commands.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def readfullfile(filename):&#xA;  with open(filename) as f:&#xA;    print(&amp;quot;opened&amp;quot;, filename)&#xA;    return f.read()&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The object returned by &lt;code&gt;open()&lt;/code&gt; implements the &lt;a href=&#34;https://docs.python.org/3/reference/datamodel.html#context-managers&#34;&gt;context&#xA;manager&lt;/a&gt;&#xA;protocol, which means that it can be used in a &lt;code&gt;with&lt;/code&gt; statement. When&#xA;the &lt;code&gt;with&lt;/code&gt;-scope exits, the cleanup functions will automatically get&#xA;invoked (e.g. to close a file).&lt;/p&gt;&#xA;&lt;p&gt;Cleanups get invoked in all cases when execution leaves the scope, no&#xA;matter whether it happens through a regular exit, an early return or&#xA;an exception.&lt;/p&gt;&#xA;&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Multiple readers have pointed out that both C# and Java&#xA;now support equivalent scoped statements as well:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;In C# with the &lt;a href=&#34;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/statements#the-using-statement&#34;&gt;&lt;code&gt;using&lt;/code&gt;&#xA;statement&lt;/a&gt;&#xA;(see&#xA;&lt;a href=&#34;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement&#34;&gt;documentation&lt;/a&gt;&#xA;and Mogens Heller Grabe&amp;rsquo;s comment with examples below).&lt;/li&gt;&#xA;&lt;li&gt;in Java with the&#xA;&lt;a href=&#34;https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.20.3.1&#34;&gt;try-with-resources&lt;/a&gt;&#xA;syntax. (&lt;a href=&#34;https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html&#34;&gt;examples&lt;/a&gt;)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;In all of these cases, the used object must implement a special&#xA;interface with a cleanup method, such as &lt;code&gt;IDisposable&lt;/code&gt; in C# and&#xA;&lt;code&gt;AutoCloseable&lt;/code&gt; in Java.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h2 id=&#34;macros-lisp&#34;&gt;Macros (Lisp)&lt;/h2&gt;&#xA;&lt;p&gt;Lisp macros are used similarly as Python&amp;rsquo;s &lt;code&gt;with&lt;/code&gt; statements, but&#xA;offer more ways to shoot yourself in the foot (Example from the book&#xA;&lt;a href=&#34;http://www.gigamonkeys.com/book/files-and-file-io.html#closing-files&#34;&gt;Practical Common&#xA;Lisp&lt;/a&gt;&#xA;by Peter Seibel):&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-lisp&#34;&gt;(with-open-file (stream &amp;quot;/some/file/name.txt&amp;quot; :direction :output)&#xA;  (format stream &amp;quot;Some text.&amp;quot;))  ; while file is opened&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Here, &lt;code&gt;with-open-file&lt;/code&gt; is a macro caring about opening and closing&#xA;(&lt;a href=&#34;http://clhs.lisp.se/Body/m_w_open.htm&#34;&gt;spec&lt;/a&gt;). The user of the macro&#xA;provides a sequence of commands to be executed with the opened file&#xA;stream, e.g. &lt;code&gt;(format stream &amp;quot;Some text.&amp;quot;)&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;These macros are often named to start with the word &lt;code&gt;with&lt;/code&gt;, but there&#xA;are exceptions, e.g. &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/eintr/save_002dexcursion.html&#34;&gt;&lt;code&gt;save-excursion&lt;/code&gt;&lt;/a&gt; in Emacs Lisp.&lt;/p&gt;&#xA;&lt;p&gt;From the caller perspective, this behaves similar as Python&amp;rsquo;s &lt;code&gt;with&lt;/code&gt;&#xA;statements, but they are usually expanded into a use of&#xA;&lt;a href=&#34;http://clhs.lisp.se/Body/s_unwind.htm&#34;&gt;&lt;code&gt;unwind-protect&lt;/code&gt;&lt;/a&gt; or a similar&#xA;primitive depending on the Lisp dialect (comparable to&#xA;&lt;code&gt;try&lt;/code&gt;&amp;hellip;&lt;code&gt;finally&lt;/code&gt;).&lt;/p&gt;&#xA;&lt;h2 id=&#34;try-finally-blocks-java-c-python-&#34;&gt;Try-Finally blocks (Java, C#, Python, &amp;hellip;)&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;try&lt;/code&gt; blocks are primarily used for catching exceptions but in many&#xA;languages they offer a &lt;code&gt;finally&lt;/code&gt; clause as well, which is guaranteed&#xA;to execute whenever the &lt;code&gt;try&lt;/code&gt; scope exits, including on early returns&#xA;and exceptions.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-java&#34;&gt;setUp();&#xA;try {&#xA;  doWork();  // between setup and cleanup&#xA;} finally {&#xA;  cleanUp();&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The construct tends to lead to deeper nesting when multiple cleanups&#xA;need to be done.&lt;/p&gt;&#xA;&lt;p&gt;Some languages have &lt;code&gt;finally&lt;/code&gt;-like constructs which are independent of&#xA;exceptions, like Smalltalk with&#xA;&lt;a href=&#34;https://www.gnu.org/software/smalltalk/manual/html_node/Hooking-into-the-stack-unwinding.html#Hooking-into-the-stack-unwinding&#34;&gt;Block&amp;raquo;ensure:&lt;/a&gt;,&#xA;&lt;a href=&#34;http://clhs.lisp.se/Body/s_unwind.htm&#34;&gt;&lt;code&gt;unwind-protect&lt;/code&gt;&lt;/a&gt; in Common&#xA;Lisp (&lt;a href=&#34;https://wiki.c2.com/?UnwindProtect&#34;&gt;on C2 wiki&lt;/a&gt;) and&#xA;&lt;a href=&#34;https://www.scheme.com/tspl4/control.html#desc:dynamic-wind&#34;&gt;&lt;code&gt;dynamic-wind&lt;/code&gt;&lt;/a&gt;&#xA;in Scheme. (Scheme has the additional complication that it needs to&#xA;deal with continuations.)&lt;/p&gt;&#xA;&lt;h2 id=&#34;todo-lists-languages-with-closures&#34;&gt;Todo lists (languages with closures)&lt;/h2&gt;&#xA;&lt;p&gt;In languages with closures or higher order functions, one way to defer&#xA;work for later is to save functions to be executed later in a list:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def frobnicate():&#xA;  todos = []&#xA;&#xA;  setUp()&#xA;  todos.append(cleanUp)&#xA;&#xA;  doWork()  # between setup and cleanup&#xA;&#xA;  for f in todos:&#xA;    f()&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;One variant of this is&#xA;&lt;a href=&#34;https://docs.python.org/3/library/unittest.html#unittest.TestCase.addCleanup&#34;&gt;&lt;code&gt;addCleanup&lt;/code&gt;&lt;/a&gt;&#xA;in Python&amp;rsquo;s &lt;code&gt;unittest&lt;/code&gt; library for deferring work to be done after the&#xA;test execution. Note that similarly to &lt;code&gt;defer&lt;/code&gt; in Go, this lets us&#xA;place the cleanup right together with the setup code, so that we can&#xA;easily keep them in sync:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;class FooTest(unittest.TestCase):&#xA;  # ...&#xA;&#xA;  def test_service(self):&#xA;    srv = StartService()&#xA;    self.addCleanup(srv.Stop)&#xA;&#xA;    self.assertEqual(42, srv.Invoke())  # while running&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: Since version 1.14, &lt;a href=&#34;/post/go-testing-cleanup/&#34;&gt;Go supports the&#xA;same&lt;/a&gt; with&#xA;&lt;a href=&#34;https://godoc.org/testing#T.Cleanup&#34;&gt;&lt;code&gt;T.Cleanup()&lt;/code&gt;&lt;/a&gt; to simplify test&#xA;cleanup.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h2 id=&#34;passing-higher-order-functions-ruby-lisp&#34;&gt;Passing higher-order functions (Ruby, Lisp?)&lt;/h2&gt;&#xA;&lt;p&gt;In Ruby, it&amp;rsquo;s common to pass down functions to other functions, as a&#xA;way of structuring control flow and also for cleanup purposes. This&#xA;invocation of&#xA;&lt;a href=&#34;https://ruby-doc.org/core-2.7.0/File.html#method-c-open&#34;&gt;&lt;code&gt;File.open&lt;/code&gt;&lt;/a&gt;&#xA;executes the passed function (in between &lt;code&gt;do&lt;/code&gt;&amp;hellip;&lt;code&gt;end&lt;/code&gt;) with the opened&#xA;file and closes the file afterwards.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-ruby&#34;&gt;File.open(&amp;quot;output.txt&amp;quot;, &amp;quot;a&amp;quot;) do |f|&#xA;  f.puts(&amp;quot;Hello, world!&amp;quot;)  # while file is open&#xA;end&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This general technique is possible in all languages where passing down&#xA;higher order functions is cheap, such as Ruby and Smalltalk. Smalltalk&#xA;takes it to another level by expressing all control flow as method&#xA;invocations, including loops and &lt;code&gt;ifTrue:&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;m not sure to what extent the Smalltalks use higher order functions&#xA;for cleanup purposes as Ruby does. More imperative Lisps like CL&#xA;expose mostly macros to users, but these will in turn use&#xA;closure-passing unwinding primitives under the hood.&lt;/p&gt;&#xA;&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;There is a technical twist here in that languages need special&#xA;guarantees for these so-called &lt;em&gt;downward funargs&lt;/em&gt; to be cheap.&lt;/p&gt;&#xA;&lt;p&gt;A &lt;em&gt;downward funarg&lt;/em&gt; is a higher-order function which is only passed&#xA;down the stack but does not outlive the stack frame in which it was&#xA;created. The captured variables referenced by a downward funarg can&#xA;happily stay on the stack. This is in contrast to upward funargs which&#xA;outlive their own stack frame and which require invisible heap&#xA;allocations or similar tricks in the language.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h2 id=&#34;setup-and-teardown-in-junit-xunit-&#34;&gt;setUp() and tearDown() in (JUnit, xUnit, &amp;hellip;)&lt;/h2&gt;&#xA;&lt;p&gt;In the &lt;em&gt;xUnit&lt;/em&gt; family of unit testing frameworks, tests are part of&#xA;classes which get executed by a test runner. Each test class may&#xA;optionally override &lt;code&gt;setUp()&lt;/code&gt; and &lt;code&gt;tearDown()&lt;/code&gt; hooks which get&#xA;executed around every test execution, independent of whether that test&#xA;succeeded or not.&lt;/p&gt;&#xA;&lt;p&gt;In languages which provide a sane way of cleanup, I think that&#xA;overriding the &lt;code&gt;tearDown()&lt;/code&gt; hook should not be necessary and probably&#xA;discouraged. I suspect the same is true for code in &lt;code&gt;setUp()&lt;/code&gt;, but&#xA;that is more related to ambient shared state which becomes tricky to&#xA;modify when multiple tests rely on a subset of it in implicit ways.&lt;/p&gt;&#xA;&lt;h2 id=&#34;discussion&#34;&gt;Discussion&lt;/h2&gt;&#xA;&lt;p&gt;These approaches are quite different to each other. In practice, the&#xA;programming language is often already fixed, and then only a limited&#xA;number of options exists.&lt;/p&gt;&#xA;&lt;p&gt;In general, I found that in practice it helps to have setup and&#xA;cleanup close to each other, so that it&amp;rsquo;s easy to keep them in sync.&#xA;Go&amp;rsquo;s &lt;code&gt;defer&lt;/code&gt; really shines there.&lt;/p&gt;&#xA;&lt;p&gt;It&amp;rsquo;s even nicer to have them represented by the same construct as with&#xA;Python&amp;rsquo;s &lt;code&gt;with&lt;/code&gt; or C++&amp;rsquo;s RAII idiom. With these, the usage becomes&#xA;safer, but you trade that for more effort in implementing classes&#xA;that are &lt;code&gt;with&lt;/code&gt;- and RAII-enabled. (In Python, this is somewhat&#xA;mitigated with the&#xA;&lt;a href=&#34;https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager&#34;&gt;&lt;code&gt;contextlib&lt;/code&gt;&lt;/a&gt;&#xA;module.)&lt;/p&gt;&#xA;&lt;p&gt;Downward funargs are both safe, easy to use and simple to implement,&#xA;but have a little overhead. That&amp;rsquo;s fair in most scripting cases, but&#xA;wouldn&amp;rsquo;t work for the Linux kernel.&lt;/p&gt;&#xA;&lt;p&gt;In terms of reasoning about performance, the Linux kernel has the&#xA;approach where it&amp;rsquo;s most obvious what this translates to at the&#xA;machine level, but the same amount of control is usually not needed in&#xA;user space programs.&lt;/p&gt;&#xA;&lt;p&gt;At a higher level, I believe it pays off to care about symmetric setup&#xA;and cleanup steps as part of the same function wherever possible. It&#xA;makes it easier to track where setups and cleanups are done across the&#xA;codebase, and refactoring to such a design reduces state that has to&#xA;be tracked across multiple functions.&lt;/p&gt;&#xA;&lt;h2 id=&#34;update-2020-01-13&#34;&gt;Update (2020-01-13)&lt;/h2&gt;&#xA;&lt;p&gt;Thanks for all the positive feedback, particularly to everyone who&#xA;pointed out related language features:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;C#&amp;rsquo;s &lt;code&gt;using&lt;/code&gt;:&lt;/strong&gt; Thanks, Mogens Heller Grabe for the longer&#xA;explanation in the comments below, as well as the users&#xA;&lt;a href=&#34;https://news.ycombinator.com/item?id=21996141&#34;&gt;hateful&lt;/a&gt; and&#xA;&lt;a href=&#34;https://news.ycombinator.com/item?id=21996141&#34;&gt;niklasjansson&lt;/a&gt; on HN&#xA;who pointed out documentation.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Java try-with-resources:&lt;/strong&gt;&#xA;&lt;a href=&#34;https://news.ycombinator.com/item?id=21997841&#34;&gt;cpt1138&lt;/a&gt; and&#xA;&lt;a href=&#34;https://news.ycombinator.com/item?id=21997848&#34;&gt;quantified&lt;/a&gt; on HN&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Rust&amp;rsquo;s &lt;code&gt;Drop&lt;/code&gt; trait:&lt;/strong&gt; &lt;a href=&#34;https://news.ycombinator.com/item?id=21998455&#34;&gt;jupp0r&lt;/a&gt; on HN&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Zig&amp;rsquo;s &lt;code&gt;defer&lt;/code&gt; and &lt;code&gt;errdefer&lt;/code&gt;:&lt;/strong&gt;&#xA;&lt;a href=&#34;https://news.ycombinator.com/item?id=21996444&#34;&gt;apta&lt;/a&gt; on HN&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;For &lt;strong&gt;Haskell&lt;/strong&gt;, &lt;a href=&#34;https://news.ycombinator.com/item?id=21998455&#34;&gt;lgas&lt;/a&gt;&#xA;mentioned the &lt;a href=&#34;https://wiki.haskell.org/Bracket_pattern&#34;&gt;Bracket&#xA;pattern&lt;/a&gt;, and&#xA;&lt;a href=&#34;https://news.ycombinator.com/item?id=21998455&#34;&gt;dwohnitmok&lt;/a&gt; is&#xA;mentioning linear types. Superficially this looks similar to&#xA;&lt;code&gt;dynamic-unwind&lt;/code&gt; and friends in Scheme and Lisp (see above), but my&#xA;Haskell-fu is too weak to judge it. I suspect it would be hard to&#xA;compare programming idioms between Haskell&amp;rsquo;s lazy purely functional&#xA;evaluation and imperative programs.&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/setup-cleanup/</guid>
      <pubDate>Wed, 08 Jan 2020 21:37:28 +0100</pubDate>
    </item>
    <item>
      <title>Mutation Testing works</title>
      <link>https://blog.gnoack.org/post/mutation-testing</link>
      <description>&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;Disclaimer: These are Google topics, but based on publicly available&#xA;resources. I&amp;rsquo;m writing this not because I get paid for it (I don&amp;rsquo;t),&#xA;but because I am truly excited about it, it&amp;rsquo;s now public, and I hope&#xA;this will find more wide-spread adoption.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Goran Petrović and Marko Ivanković have published a nice paper on the&#xA;&lt;a href=&#34;https://research.google/pubs/pub46584/&#34;&gt;&amp;ldquo;State of Mutation Testing at&#xA;Google&amp;rdquo;&lt;/a&gt; a while&#xA;ago&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;m a fan of this, because &lt;a href=&#34;https://en.m.wikipedia.org/wiki/Mutation_testing&#34;&gt;Mutation&#xA;Testing&lt;/a&gt; spots real&#xA;test coverage issues which regular line-based coverage won&amp;rsquo;t&#xA;catch. The approach presented in the paper runs mutation testing in&#xA;the context of a code review, which narrows the surfaced issues to the&#xA;code you&amp;rsquo;re already working on, and keeps them actionable.&lt;/p&gt;&#xA;&lt;h2 id=&#34;example&#34;&gt;Example&lt;/h2&gt;&#xA;&lt;p&gt;To get an idea how the approach in the paper works in practice: Let&amp;rsquo;s&#xA;assume we send a code review introducing a line such as &lt;code&gt;if (a == b || b == 1) {&lt;/code&gt;, but we didn&amp;rsquo;t bother testing the new code properly. With&#xA;mutation testing enabled, the infrastructure would now catch us and&#xA;report something like this (from page 2 in the paper):&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;Changing this 1 line to&#xA;&#xA;  if (a != b || b == 1) {&#xA;&#xA;does not cause any test exercising them to fail.&#xA;&#xA;Consider adding test cases that fail when the code is mutated to&#xA;ensure those bugs would be caught.&#xA;&#xA;Mutants ran because goranpetrovic is whitelisted.&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2 id=&#34;how-did-it-figure-that-out&#34;&gt;How did it figure that out?&lt;/h2&gt;&#xA;&lt;p&gt;Mutation Testing runs on a proposed change during a code review, so&#xA;the problem is defined (a) through a bunch of changes to production&#xA;code and (b) implicitly through the tests exercising that code.&lt;/p&gt;&#xA;&lt;p&gt;The mutation testing infrastructure now attempts the following:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;Purposefully modify program logic&lt;/strong&gt; in the code under test&#xA;(e.g. negate an &lt;code&gt;if&lt;/code&gt; condition)&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Check if any of the tests starts failing&lt;/strong&gt;.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;We messed up the code under test, so with good &amp;ldquo;logical coverage&amp;rdquo;, one&#xA;of the tests should now have failed.  But if all tests have still&#xA;passed, we apparently have changed logic that wasn&amp;rsquo;t properly tested.&lt;/p&gt;&#xA;&lt;h2 id=&#34;mutation-testing-is-underrated&#34;&gt;Mutation Testing is underrated&lt;/h2&gt;&#xA;&lt;p&gt;Even though it looks like it&amp;rsquo;s originally coming from a more academic&#xA;corner, &lt;strong&gt;Mutation Testing works in practice.&lt;/strong&gt; The examples in the&#xA;paper are not made up, and they saved me from real bugs.&lt;/p&gt;&#xA;&lt;p&gt;I hope that there will be more implementations in the wild at some&#xA;point. It&amp;rsquo;s worth the effort.&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;Google started publishing more material on&#xA;internal developer tooling in the recent years. I ♥ it because I&#xA;can now point to papers rather than to Google PR when people ask&#xA;about it. :)&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;The list of implemented mutations is at the top of page&#xA;4 in the paper.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/mutation-testing/</guid>
      <pubDate>Mon, 30 Dec 2019 23:53:19 +0100</pubDate>
    </item>
    <item>
      <title>Wireguard is in the Linux kernel</title>
      <link>https://blog.gnoack.org/post/wireguard</link>
      <description>&lt;p&gt;I&amp;rsquo;m very happy to hear that &lt;a href=&#34;https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=e7096c131e5161fa3b8e52a650d7719d2857adfd&#34;&gt;Wireguard has made it into the Linux&#xA;kernel&lt;/a&gt;&#xA;and &lt;a href=&#34;https://lists.zx2c4.com/pipermail/wireguard/2019-December/004704.html&#34;&gt;will be part of Linux&#xA;5.6&lt;/a&gt;!&lt;/p&gt;&#xA;&lt;p&gt;Wireguard was quite a relief for me after wrestling with OpenVPN&#xA;before, for multiple reasons. I&amp;rsquo;m a happy user for about a year now,&#xA;and I can wholeheartedly recommend it.&lt;/p&gt;&#xA;&lt;p&gt;Wireguard is really pushing the state of the art forward for VPNs:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;high performance&lt;/strong&gt; (it&amp;rsquo;s part of the kernel)&lt;/li&gt;&#xA;&lt;li&gt;very &lt;strong&gt;simple setup&lt;/strong&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;no wrestling with OpenSSL or X.509 certificates&lt;/li&gt;&#xA;&lt;li&gt;key management&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; comparable to OpenSSH, &lt;strong&gt;keys fit one line&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;excellent apps&lt;/strong&gt; for&#xA;&lt;a href=&#34;https://play.google.com/store/apps/details?id=com.wireguard.android&#34;&gt;Android&lt;/a&gt;&#xA;and &lt;a href=&#34;https://apps.apple.com/de/app/wireguard/id1441195209&#34;&gt;iOS&lt;/a&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;full config files can be provided as QR codes&lt;/li&gt;&#xA;&lt;li&gt;it &lt;strong&gt;does not drain&lt;/strong&gt; your battery (a mostly stateless protocol)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.wireguard.com/install/&#34;&gt;support for many platforms&lt;/a&gt;&#xA;apart from Linux through a user space implementation&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;an-example-configuration&#34;&gt;An example configuration&lt;/h2&gt;&#xA;&lt;p&gt;To get an idea, this is a &lt;code&gt;/etc/wireguard/wg0.conf&lt;/code&gt; configuration file&#xA;very similar&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; to the one I use on my Laptop right now:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-ini&#34;&gt;[Interface]&#xA;PrivateKey = WG8r5DNvD2KlZORhJ2XgzW3lWO8i5GJqZBePt98EgUY=&#xA;Address = 192.168.23.10/32&#xA;DNS = 192.168.23.1&#xA;&#xA;[Peer]&#xA;PublicKey = 6qzH9hJbyPFp+GJJoxsBaPhUEl4mVKTGNP433xLWhBc=&#xA;PresharedKey = LiWmdHZN/Jizhv1h0qTGeslci2yZIyrkEDjrx3bUomE=&#xA;AllowedIPs = 0.0.0.0/0, ::/0&#xA;Endpoint = vpn.gnoack.org:9999&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This contains our own device&amp;rsquo;s private key and configured IP in the&#xA;VPN, as well as a list of peer hosts with their public keys and the IP&#xA;addresses they are making available.&lt;/p&gt;&#xA;&lt;p&gt;Note the symmetry: A server-side configuration looks the&#xA;same, but with more peer entries.&lt;/p&gt;&#xA;&lt;p&gt;The command &lt;code&gt;wg-quick up wg0&lt;/code&gt; brings the configuration up as a new device and sets&#xA;appropriate routes.&lt;/p&gt;&#xA;&lt;p&gt;For further reference, &lt;a href=&#34;https://www.wireguard.com/quickstart/&#34;&gt;Wireguard&amp;rsquo;s own quickstart&#xA;page&lt;/a&gt; has a better introduction&#xA;than this one here (with a video).&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: I&amp;rsquo;m not affiliated with Wireguard, but I received a&#xA;big stack of stickers&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; from Jason Donenfeld after a talk&#xA;once. Congratulations on the big step forward, and thanks for the&#xA;great software!&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;Key management can hardly be simpler than that:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;$ wg genkey &amp;gt; beuys.gnoack.org&#xA;$ wg pubkey &amp;lt; beuys.gnoack.org&#xA;tw6MlpAFMoQInDC402FndO8Z49/H4cT11BYOHDRkcys=&#xA;$ wg genpsk &amp;gt; psk&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This is a breeze compared to the OpenSSL dance required to get OpenVPN running.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;These are example values, of course.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:3&#34;&gt;&#xA;&lt;p&gt;That was really nice. As everyone knows, stickers beat&#xA;Bitcoin and Ethereum hands down as an underground hacker&#xA;currency. :) They were quite popular in the sticker exchange where&#xA;I placed them. 🐉&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/wireguard/</guid>
      <pubDate>Mon, 09 Dec 2019 22:59:00 +0200</pubDate>
    </item>
    <item>
      <title>Go: Goroutines and Apis</title>
      <link>https://blog.gnoack.org/post/go-goroutines-and-apis</link>
      <description>&lt;p&gt;Goroutines are a unusual and powerful programming language feature, so&#xA;they are a tempting toy to play with, and they get a bit overused.&lt;/p&gt;&#xA;&lt;p&gt;There is some indication that the following Go principle holds true:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Strive to provide synchronous APIs,&lt;br&gt;&#xA;let the caller start goroutines.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;To put this advice into a more concrete code example:&lt;/p&gt;&#xA;&lt;p&gt;Do this:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-golang&#34;&gt;func (t *type) Run(ctx context.Context) {&#xA;    // Implementation of background task&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Instead of this:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-golang&#34;&gt;func (t *type) Start() {&#xA;    t.wg.Add(1)&#xA;    go func() {&#xA;      // Implementation of background task&#xA;      t.wg.Done()&#xA;    }&#xA;}&#xA;&#xA;func (t *type) Cancel() {&#xA;    // Somehow cancel the background task&#xA;    t.wg.Wait()&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Upsides for &lt;code&gt;Run()&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The caller gets to decide how the &amp;ldquo;background&amp;rdquo; code gets run.&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Spawning Goroutines is easy for the caller too.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;go&lt;/code&gt; statements move towards the application&amp;rsquo;s top-level.&#xA;Goroutine coordination becomes simpler to reason about when&#xA;goroutines are started in fewer places.&lt;/li&gt;&#xA;&lt;li&gt;Callers can also run it without goroutine and just block on the&#xA;call, if there is no other work to be done.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Background task cancellation is provided through the context.&lt;/li&gt;&#xA;&lt;li&gt;Waiting for the background task has a trivial API (when the&#xA;function returns), and can be done with the mechanism the&#xA;caller prefers (waitgroups, channels, &amp;hellip;)&lt;/li&gt;&#xA;&lt;li&gt;It&amp;rsquo;s on the safe side API-wise: There is no &lt;code&gt;Close()&lt;/code&gt; method which&#xA;callers can forget to call (leaking resources).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Another great discussion of this was in the &lt;a href=&#34;https://changelog.com/gotime/102#transcript-91&#34;&gt;Go Time: On application&#xA;design&lt;/a&gt; podcast&#xA;(starting around minute 47, Mat Ryer&amp;rsquo;s explanation really resonated&#xA;with me)&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Addendum&lt;/strong&gt;: In the comments, Jacob is pointing out the talk &lt;a href=&#34;https://www.youtube.com/watch?v=LHe1Cb_Ud_M&#34;&gt;&amp;ldquo;Ways&#xA;To Do Things&amp;rdquo; by Peter&#xA;Bourgon&lt;/a&gt;&#xA;&lt;a href=&#34;https://speakerdeck.com/peterbourgon/ways-to-do-things?slide=14&#34;&gt;(slides)&lt;/a&gt;,&#xA;who also appeared on the above &amp;ldquo;Go Time&amp;rdquo; episode. The talk describes&#xA;the &lt;code&gt;Run()&lt;/code&gt; style quite clearly and in more detail. Thanks for the&#xA;excellent pointer, Jacob!&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/go-goroutines-and-apis/</guid>
      <pubDate>Mon, 18 Nov 2019 21:30:53 +0100</pubDate>
    </item>
    <item>
      <title>Go: Error handling</title>
      <link>https://blog.gnoack.org/post/go-errors</link>
      <description>&lt;img src=&#34;/images/rakegopher.png&#34;&gt;&#xA;&lt;p&gt;I love Go for many reasons, but this part is still itching me: I&#xA;postulate that this Go idiom is a burden on our mental capacity:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-golang&#34;&gt;if err != nil {&#xA;        return nil&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;a href=&#34;/post/error_handling&#34;&gt;Error handling&lt;/a&gt; is at a tension between two&#xA;different developer needs.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;On the one hand, error handling is very annoying and distracting&#xA;when working on a constructively formulated use case.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;On the other hand, not dealing with it correctly means that the&#xA;program blows up in unknown ways when errors happen: data may be lost,&#xA;I/O may be half done, features may stop working without the developers&#xA;noticing.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Go&amp;rsquo;s explicitness about error handling makes sure that errors are not&#xA;falling through the cracks as easily as they might do in other&#xA;languages where errors are implicitly propagated&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;. While many&#xA;developers love Go&amp;rsquo;s explicitness, it is rather verbose for error&#xA;handling, which has drawbacks:&lt;/p&gt;&#xA;&lt;p&gt;(1) &lt;strong&gt;Humans are pattern matching machines&lt;/strong&gt;. Whenever we see text&#xA;whose shape resembles the error checking idiom, we have trained&#xA;ourselves to quickly look away, at the more important code next to it.&#xA;But bugs can hide even in repetitive parts of the code. If we&amp;rsquo;re not&#xA;looking at the idiom anyway, the &lt;code&gt;try()&lt;/code&gt; proposal might be the better&#xA;option, as it de-duplicates the check.&lt;/p&gt;&#xA;&lt;p&gt;(2) &lt;strong&gt;The error handling pattern takes much visual space&lt;/strong&gt;. The idiom&#xA;is necessarily interleaved with the code on the happy path. In many&#xA;cases, the flow of reading a longer function is interrupted multiple&#xA;times with the same 3-line code snippet.&lt;/p&gt;&#xA;&lt;h2 id=&#34;two-different-hats&#34;&gt;Two different hats&lt;/h2&gt;&#xA;&lt;p&gt;I believe that reasoning about constructive code and reasoning about&#xA;error handling code are &lt;em&gt;two separate states of mind&lt;/em&gt;, and switching&#xA;back and forth between these is straining and tedious&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;&#xA;&lt;p&gt;A consequence of this is: It might be more productive to spend less&#xA;time on errors during an initial implementation, and to then address&#xA;the error handling aspect in a separate pass over the code. It&#xA;would be better if we could have two views of the code for these&#xA;different modes of operation:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;For the feature-focused mode, we need a view of the code where the&#xA;error handling stays explicit&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;, but goes out of the way visually in&#xA;order to make the constructive code more prominent.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;For the error-focused mode, an error-only view is not really&#xA;possible because errors happen only as a result of constructive&#xA;operations, but in many editors, an interactive search for the&#xA;keywords &lt;code&gt;return&lt;/code&gt; and &lt;code&gt;try&lt;/code&gt;(?) will highlight the possible exit points&#xA;quickly.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I think this would have been well solved with &lt;a href=&#34;https://github.com/golang/go/issues/32437&#34;&gt;Robert Griesemer&amp;rsquo;s&#xA;&lt;code&gt;try()&lt;/code&gt; proposal&lt;/a&gt;. I&amp;rsquo;m&#xA;still sad it didn&amp;rsquo;t go forward, but I&amp;rsquo;m glad the Go team is so careful&#xA;about it.&lt;/p&gt;&#xA;&lt;p&gt;Just because we have all already invested so much time into accepting&#xA;this verbose way of error handling, that doesn&amp;rsquo;t mean it&amp;rsquo;s a good&#xA;thing&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;This is particularly true for languages with exceptions where all function calls may implicitly throw exceptions and bubble them up the stack.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;It&amp;rsquo;s the same as trying to write a scientific article straight in LaTeX form: You can somehow do it, but the first formula will derail your train of thought so hard that the article will probably suffer from it. It&amp;rsquo;s a better option to write the article in a different medium and then do the translation to LaTeX in a separate step.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:3&#34;&gt;&#xA;&lt;p&gt;Explicitness is a stated goal in Go, after all.&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:4&#34;&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://en.wikipedia.org/wiki/Sunk_cost&#34;&gt;sunk cost effect&lt;/a&gt; is strong for programming languages! But then again, it&amp;rsquo;s much worse for C++. :)&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/go-errors/</guid>
      <pubDate>Fri, 18 Oct 2019 20:00:00 +0200</pubDate>
    </item>
    <item>
      <title>Dot Space Space</title>
      <link>https://blog.gnoack.org/post/dot-space-space</link>
      <description>&lt;p&gt;I have a confession to make. I used to put two spaces after each&#xA;sentence, as it used to be done by typewriter typists before computers&#xA;[citation needed].&lt;/p&gt;&#xA;&lt;p&gt;The moment when I started to form this habit was around 2010. I was&#xA;young and easy to impress, and I was picking up more advanced Emacs&#xA;use working on the TeX source for my diploma thesis. While editing&#xA;these large chunks of free-form text was when I discovered the&#xA;&lt;code&gt;fill-paragraph&lt;/code&gt; function, otherwise known as &lt;code&gt;M-q&lt;/code&gt;, for automatically&#xA;breaking text at the correct column width. This is very useful for&#xA;editing text files, so it quickly became a habit to press &lt;code&gt;M-q&lt;/code&gt; often.&#xA;I&amp;rsquo;m still using it right now, in fact.&lt;/p&gt;&#xA;&lt;p&gt;Now after a while of using this feature, I started to observe that&#xA;this didn&amp;rsquo;t work exactly how I thought. Readjusting text where one&#xA;line ends with a full stop, it would surprisingly add two spaces in&#xA;the middle after breaking.&lt;/p&gt;&#xA;&lt;p&gt;This text:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;Hello world.&#xA;This is a text.&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Would turn into that text after a press of &lt;code&gt;M-q&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;Hello world.  This is a text.&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Then somewhere in Emacs documentation, I found key bindings jump back&#xA;and forth between sentences (&lt;code&gt;M-a&lt;/code&gt;, &lt;code&gt;M-e&lt;/code&gt;), and these also rely on&#xA;double-spaces to tell apart sentence ends from abbreviations (e.g. as&#xA;in Dr. Seuss).&lt;/p&gt;&#xA;&lt;p&gt;I did not end up picking up these shortcuts, but it was enough for me&#xA;to rationalize the double spaces. In reality of course, I only started&#xA;with that habit so that &lt;code&gt;M-q&lt;/code&gt; would not break the otherwise consistent&#xA;spacing style accidentally.&lt;/p&gt;&#xA;&lt;p&gt;I used this for about 10 years now, and of course it didn&amp;rsquo;t elude me&#xA;that I was the only one doing that, but it&amp;rsquo;s hard to put down old&#xA;habits.&lt;/p&gt;&#xA;&lt;p&gt;Recently, I found what I think is the remedy - &lt;code&gt;M-q&lt;/code&gt; is actually&#xA;configurable in Emacs, and the old habit of pressing &lt;code&gt;M-q&lt;/code&gt; will now&#xA;just fix my sentences to single-spaces again going forward.&lt;/p&gt;&#xA;&lt;p&gt;This is what is needed:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-elisp&#34;&gt;(setq sentence-end-double-space nil)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;What do we learn from this story? I&amp;rsquo;m not sure. Maybe that old habits&#xA;are hard to shake. Some quirks creep in without you noticing and a&#xA;tiny change might fix them.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;M-q&lt;/code&gt;&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/dot-space-space/</guid>
      <pubDate>Fri, 30 Aug 2019 09:17:30 +0200</pubDate>
    </item>
    <item>
      <title>Notes on Plan9&#39;s 9P protocol</title>
      <link>https://blog.gnoack.org/post/9pnotes</link>
      <description>&lt;p&gt;The 9P protocol is the protocol for network file systems used in&#xA;Plan9.  Plan9 is not a widely used operating system, but it&amp;rsquo;s widely&#xA;considered more true to the Unix spirit than Unix is, coming from some&#xA;of the same people who made Unix as well.&lt;/p&gt;&#xA;&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;&#xA;&lt;p&gt;To get a rough idea of the 9P protocol, consider a system where all&#xA;the original core Unix syscalls (&lt;code&gt;open&lt;/code&gt;, &lt;code&gt;close&lt;/code&gt;, &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;write&lt;/code&gt;,&#xA;&amp;hellip;)  are lifted to be remote procedure calls.  These can be sent over&#xA;the network, making file systems in Plan9 network transparent.&lt;/p&gt;&#xA;&lt;p&gt;9P&amp;rsquo;s RPCs are documented in Plan9&amp;rsquo;s man page section 5&#xA;(&lt;a href=&#34;http://man.cat-v.org/plan_9/5/&#34;&gt;mirror&lt;/a&gt;). The supported methods are:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Session control&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;version&lt;/code&gt; to negotiate the protocol version.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;attach&lt;/code&gt; and &lt;code&gt;auth&lt;/code&gt; for authenticating with the remote end and opening a session.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;flush&lt;/code&gt; to cancel ongoing requests.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Basic file operations:&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;open&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;clunk&lt;/code&gt; (equivalent to &lt;code&gt;close&lt;/code&gt;)&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;read&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;write&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Working with directories&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;walk&lt;/code&gt; to descend a directory hierarchy.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;stat&lt;/code&gt; and &lt;code&gt;wstat&lt;/code&gt; for querying and modifying a directory entries&#xA;(e.g. to rename files).&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;remove&lt;/code&gt; for removing file entries.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;In addition, there is an &lt;code&gt;error&lt;/code&gt; response which may be returned as&#xA;response to any of these requests.&lt;/p&gt;&#xA;&lt;p&gt;The handle to a file is called &amp;ldquo;file ID&amp;rdquo; (fid) in Plan9 lingo.  This&#xA;can be thought of as a file descriptor.&lt;/p&gt;&#xA;&lt;p&gt;The 9P protocol does away with a bunch of complexities that Unix, and&#xA;particularly Linux has started to have.  Some of the non-supported&#xA;features are:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;There is no &lt;code&gt;mmap&lt;/code&gt; support in the protocol.  This can&amp;rsquo;t be done over the network.&#xA;Presumably it can be emulated within limits if needed.&lt;/li&gt;&#xA;&lt;li&gt;No &lt;code&gt;ioctl&lt;/code&gt;.  Control-style operations are often done through reads and writes&#xA;to special purpose files.  There are often textual command languages.&lt;/li&gt;&#xA;&lt;li&gt;There is a more blurry line between different file types as in Unix,&#xA;where you can distinguish named pipes, device files and regular files.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;playing-with-plan9port&#34;&gt;Playing with Plan9port&lt;/h2&gt;&#xA;&lt;p&gt;An easy way to play with 9P is to install Plan9port, a Linux userspace&#xA;port of Plan9&amp;rsquo;s core tools and wiring, which comes as installable&#xA;package with many Linux distributions.&lt;/p&gt;&#xA;&lt;p&gt;Plan9port includes the Plan9 compiler, the acme text editor and other&#xA;things, including source code.  Many of these tools are exposing 9P&#xA;file systems over Unix sockets in the &lt;code&gt;/tmp/ns.$USER.$DISPLAY&lt;/code&gt;&#xA;directory.  You can get your exact location by running the &lt;code&gt;namespace&lt;/code&gt;&#xA;tool:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;$ namespace&#xA;/tmp/ns.me:0&#xA;$&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;For example, you might want to start up the &lt;code&gt;factotum&lt;/code&gt; authentication&#xA;service and have a peek at the created file system.  Plan9port&amp;rsquo;s &lt;code&gt;9p&lt;/code&gt;&#xA;tool lets you do simple accesses from the command line:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;$ /usr/lib/plan9/bin/factotum&#xA;$ ls $(namespace)&#xA;factotum&#xA;$ 9p ls factotum&#xA;confirm&#xA;conv&#xA;ctl&#xA;log&#xA;needkey&#xA;proto&#xA;rpc&#xA;$&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;There are also public 9P services, such as the Plan9 &amp;ldquo;sources&amp;rdquo;&#xA;repository.  After the Bell Labs server went down, these continue to&#xA;be mirrored by services such as &lt;code&gt;sources.9p.io&lt;/code&gt;.  The &lt;code&gt;9fs&lt;/code&gt; script is&#xA;a wrapper for quickly mounting this remote service, but needs a little&#xA;modification for convenience:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;$ cat $PLAN9/bin/9fs \&#xA;  | sed -e &#39;s/sources.cs.bell-labs.com/sources.9p.io/&#39; &amp;gt; ~/9fs&#xA;$ chmod +x ~/9fs&#xA;$ ~/9fs sources&#xA;$ 9p ls -l sources&#xA;d-rwxrwxr-x M 0 9grid  9grid       0 Jul 15  2018 9grid&#xA;--rw-rw-r-- M 0 bootes sys         0 Jun 24  2013 _sources&#xA;d-rwxrwxr-x M 0 adm    sys         0 Jul 15  2018 adm&#xA;d-rwxrwxr-x M 0 sys    sys         0 Oct 28 19:18 contrib&#xA;d-rwxrwxr-x M 0 bootes sys         0 Jul 15  2018 dist&#xA;d-rwxrwxr-x M 0 sys    sys         0 Jul 15  2018 extra&#xA;--rw-rw-r-- M 0 bootes adm   9142602 Jan 23  2015 lsr&#xA;d-rwxrwxr-x M 0 geoff  nix         0 Jul 15  2018 nix&#xA;d-rwxrwxrwx M 0 glenda sys         0 Jul 15  2018 patch&#xA;d-rwxrwxr-x M 0 sys    sys         0 Jul 15  2018 plan9&#xA;d-rwxrwxr-x M 0 sys    sys         0 Jul 15  2018 wiki&#xA;d-rwxrwxr-x M 0 xen    xen         0 Jul 15  2018 xen&#xA;$&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;&lt;strong&gt;💡 Hint&lt;/strong&gt;: To make browsing more convenient, you may also use the FUSE&#xA;file system which comes with Plan9port:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;$ 9pfuse unix\!/tmp/ns.$USER.:0/sources /tmp/sources&#xA;$ ls /tmp/sources&#xA;9grid  contrib  extra  nix    plan9     wiki&#xA;adm    dist     lsr    patch  _sources  xen&#xA;$&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h2 id=&#34;looking-under-the-hood&#34;&gt;Looking under the hood&lt;/h2&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s first read a small file from the Plan9 sources repo:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;$ 9p read sources/plan9/NOTICE&#xA;Copyright © 2002 Lucent Technologies Inc.&#xA;All Rights Reserved&#xA;$&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;To look under the hood of 9P, we can use the &lt;code&gt;9p&lt;/code&gt; tool&amp;rsquo;s &lt;code&gt;-D&lt;/code&gt; option&#xA;to print all requests and responses.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;$ 9p -D read sources/plan9/NOTICE&#xA;&amp;lt;- Tversion tag 0 msize 8192 version &#39;9P2000&#39;&#xA;-&amp;gt; Rversion tag 65535 msize 8192 version &#39;9P2000&#39;&#xA;&amp;lt;- Tauth tag 0 afid 0 uname me aname &amp;lt;nil&amp;gt;&#xA;-&amp;gt; Rerror tag 0 ename authentication rejected&#xA;&amp;lt;- Tattach tag 0 fid 0 afid -1 uname me aname&#xA;-&amp;gt; Rattach tag 0 qid (0000000000000002 0 d)&#xA;&amp;lt;- Twalk tag 0 fid 0 newfid 1 nwname 2 0:plan9 1:NOTICE&#xA;-&amp;gt; Rwalk tag 0 nwqid 2 0:(0000000000081aa0 78 d) 1:(0000000000081d2d 1 )&#xA;&amp;lt;- Topen tag 0 fid 1 mode 0&#xA;-&amp;gt; Ropen tag 0 qid (0000000000081d2d 1 ) iounit 8168&#xA;&amp;lt;- Tread tag 0 fid 1 offset 0 count 4096&#xA;-&amp;gt; Rread tag 0 count 63 &#39;436f7079 72696768 7420c2a9 20323030 32204c75 ...&#39;&#xA;Copyright © 2002 Lucent Technologies Inc.&#xA;All Rights Reserved&#xA;&amp;lt;- Tread tag 0 fid 1 offset 63 count 4096&#xA;-&amp;gt; Rread tag 0 count 0 &#39;&#39;&#xA;&amp;lt;- Tclunk tag 0 fid 1&#xA;-&amp;gt; Rclunk tag 0&#xA;$&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The &lt;code&gt;9p&lt;/code&gt; tool opens the Unix socket at &lt;code&gt;/tmp/ns.me.:0/sources&lt;/code&gt; to talk&#xA;to the backend service.&lt;/p&gt;&#xA;&lt;p&gt;The steps are:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Version negotiation: Both sides confirm the 9P variant they want&#xA;to speak.&lt;/li&gt;&#xA;&lt;li&gt;Authentication: The &lt;code&gt;auth&lt;/code&gt; call is normally supposed to return an&#xA;open file ID, over which to speak an authentication protocol. In&#xA;this case, the service permits unauthenticated read accesses, so&#xA;this is returning an error.&lt;/li&gt;&#xA;&lt;li&gt;Attaching to the service, retrieving the desired root directory,&#xA;in this case it&amp;rsquo;s just the root.&#xA;(Note, the client picks which FID it would like to use for&#xA;identifying files.)&lt;/li&gt;&#xA;&lt;li&gt;Walking down to the desired file from the root FID 0, yielding&#xA;the new FID 1.&lt;/li&gt;&#xA;&lt;li&gt;Opening the FID for reading.&lt;/li&gt;&#xA;&lt;li&gt;Calling &lt;code&gt;read&lt;/code&gt; until nothing is returned any more.&lt;/li&gt;&#xA;&lt;li&gt;Closing the FID with &lt;code&gt;clunk&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;some-resources&#34;&gt;Some resources&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;http://9p.cat-v.org/documentation/&#34;&gt;9p.cat-v.org/documentation&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;http://man.cat-v.org/plan_9/5/intro&#34;&gt;Plan9 intro(5)&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://blog.aqwari.net/9p/&#34;&gt;Writing a 9P server form scratch&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/9pnotes/</guid>
      <pubDate>Fri, 22 Mar 2019 12:26:34 +0100</pubDate>
    </item>
    <item>
      <title>How to review code</title>
      <link>https://blog.gnoack.org/post/code_reviews</link>
      <description>&lt;figure&gt;&#xA;&lt;img src=&#34;/images/2011.09.18_code_reviews.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;figcaption&gt;&lt;p&gt;A code review that doesn&amp;rsquo;t go right. (image by &lt;a href=&#34;http://www.bonkersworld.net&#34;&gt;Manu Cornet&lt;/a&gt;, CC BY-NC-ND 3.0&lt;/p&gt;&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;I&amp;rsquo;ve reviewed over 3000 code changes so far in my career, and gone&#xA;through about same amount of reviews as change author.  When reviewing&#xA;code, here is the golden rule I follow:&lt;/p&gt;&#xA;&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;Any code change that&amp;rsquo;s a strict improvement should be approved.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Most incoming code reviews are both improvements in some aspects and&#xA;make things worse in other aspects.&lt;/p&gt;&#xA;&lt;h2 id=&#34;understand-the-change&#34;&gt;Understand the change&lt;/h2&gt;&#xA;&lt;p&gt;It&amp;rsquo;s tempting to glance over a change and only comment on small&#xA;technical details or style issues, but this will eventually lead to&#xA;worse code.  In order to give meaningful feedback, understand the&#xA;change to the extent where you could have authored it yourself.&lt;/p&gt;&#xA;&lt;h2 id=&#34;blocking-issues-to-look-out-for&#34;&gt;Blocking issues to look out for&lt;/h2&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;New code is unclear.&lt;/strong&gt; Ask: &amp;ldquo;I do not understand this&amp;rdquo;.  Insist&#xA;that it&amp;rsquo;s clarified in the final submitted code rather than in a&#xA;review comment.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;New code is missing tests.&lt;/strong&gt; Insist.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;New code does not fit into surrounding code&lt;/strong&gt; in terms of style&#xA;or common libraries used.  Insist.  Link to a canonical style guide&#xA;whenever you can.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Pre-existing tests were changed willy-nilly until they run&#xA;green.&lt;/strong&gt; This often takes the form of only a few lines added to&#xA;every existing test case.  These drive-by fixes accumulate easily&#xA;over the course of some changes, until the core idea behind the&#xA;test cases is obstructed.  Insist on refactoring the tests.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;New code introduces duplication&lt;/strong&gt; with existing code.  Ask to&#xA;deduplicate.  (This is particularly often seen in tests.)&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;The change is increasing code complexity.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Is there a better solution you can suggest?&lt;/li&gt;&#xA;&lt;li&gt;Does the change&amp;rsquo;s benefit outweigh the additional complexity?&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;The change introduces dependencies in places where they don&amp;rsquo;t&#xA;belong.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;non-blocking-issues-to-look-out-for&#34;&gt;Non-blocking issues to look out for&lt;/h2&gt;&#xA;&lt;p&gt;It&amp;rsquo;s fine to ask for additional changes that are not strictly&#xA;required, but always make it clear that they are optional.&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;&amp;ldquo;I would have done it differently.&amp;rdquo;&lt;/strong&gt; is a gut reaction almost&#xA;all reviewers have sometimes.  But it&amp;rsquo;s a shortcut heuristic the&#xA;mind takes which usually has a more solid technical background.&lt;/p&gt;&#xA;&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;Learn the specific technical background to your gut&#xA;reactions, so you can give concrete advice.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;If you can&amp;rsquo;t find a specific technical problem, consider asking why&#xA;it was done in that particular way.  There are often be good&#xA;reasons which only need to be clarified a bit in the code.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Pre-existing issues.&lt;/strong&gt; Point out if pre-existing issues can be&#xA;fixed in the same change, but explicitly mark it as optional.  Even&#xA;when not done immediately, this discussion helps to form a common&#xA;understanding which pre-existing patterns in the code should be&#xA;avoided and kept.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;taking-technical-debt-a-game-of-trust&#34;&gt;Taking technical debt: A game of trust&lt;/h2&gt;&#xA;&lt;p&gt;Sometimes you will want to approve newly introduced issues and&#xA;postpone their fixes until later&#xA;(&lt;a href=&#34;https://en.m.wikipedia.org/wiki/Technical_debt&#34;&gt;Technical debt&lt;/a&gt;).&#xA;Insist that the author will fix these issues after the submission.&lt;/p&gt;&#xA;&lt;p&gt;In these cases, code reviews are a game of trust.  A strategy that&#xA;works for me is: Assume the best from people you don&amp;rsquo;t know yet, but&#xA;don&amp;rsquo;t let them pass a second time if they didn&amp;rsquo;t pay off the technical&#xA;debt.&lt;/p&gt;&#xA;&lt;p&gt;Good ways to track technical debt issues are (1) a good memory for&#xA;names, (2) a shared bug tracker and (3) &lt;code&gt;TODO&lt;/code&gt; markers in the code&#xA;(for smaller things).&lt;/p&gt;&#xA;&lt;h2 id=&#34;behaviors-to-avoid-as-a-reviewer&#34;&gt;Behaviors to avoid as a reviewer&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Do not sit on a code review.&lt;/strong&gt; Even if you can&amp;rsquo;t do the review,&#xA;explain immediately why you can&amp;rsquo;t do it (yet) and redirect to&#xA;someone better suited if possible.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Never insist that reviewees fix pre-existing issues.&lt;/strong&gt; Being code&#xA;reviewer is a position of power, but it&amp;rsquo;s not a free pass to&#xA;blackmail others into doing your work.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Don&amp;rsquo;t block legitimate changes for corporate politics reasons.&lt;/strong&gt;&#xA;This should go without saying.  Do not use code reviews to unjustly&#xA;influence project priorities.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;parting-words&#34;&gt;Parting words&lt;/h2&gt;&#xA;&lt;p&gt;I hope this collection of code reviewing tips will help someone to&#xA;have more constructive code reviews. Remember:&lt;/p&gt;&#xA;&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;The reviewer&amp;rsquo;s job is not to stand in the way, but to enable&#xA;the code submitter to do their best work.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Feedback is always appreciated. :)&lt;/p&gt;&#xA;&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;&lt;strong&gt;Update 2019-09-05:&lt;/strong&gt;&#xA;My colleague &lt;a href=&#34;https://twitter.com/mkanat&#34;&gt;Max Kanat-Alexander&lt;/a&gt; has&#xA;compiled and open sourced Google&amp;rsquo;s guidelines for code reviews at&#xA;&lt;a href=&#34;https://google.github.io/eng-practices/&#34;&gt;https://google.github.io/eng-practices/&lt;/a&gt;. It&amp;rsquo;s a longer document&#xA;compiled from the input of many engineers and has a lot of good&#xA;advice. I can wholeheartedly endorse this.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/code_reviews/</guid>
      <pubDate>Thu, 14 Mar 2019 13:00:06 +0200</pubDate>
    </item>
    <item>
      <title>Procedurally generated trees</title>
      <link>https://blog.gnoack.org/post/trees</link>
      <description>&lt;script src=&#34;https://blog.gnoack.org/js/paper-full.min.js&#34;&gt;&lt;/script&gt;&#xA;&lt;figure class=&#34;nomargin&#34;&gt;&#xA;&lt;script type=&#34;text/paperscript&#34; canvas=&#34;trees&#34;&gt;&#xA;var x = new Point(1, 0);&#xA;var y = new Point(0, 1);&#xA;function config(treeColor, leafColor) {&#xA;    return {&#xA;        treeColor: treeColor,&#xA;        leafColor: leafColor&#xA;    }&#xA;}&#xA;function leaf(pt, angle, length, cfg) {&#xA;  var r = length / 3;&#xA;  var tip = pt - y*length;&#xA;  var mid = pt - y*(length/2);&#xA;  var l = new Path([&#xA;      new Segment(pt, - x*r, + x*r),&#xA;      new Segment(tip, + x*(r/2), - x*(r/2)),&#xA;      new Segment(pt, - x*r, + x*r)&#xA;  ]);&#xA;  l.rotate(angle, pt);&#xA;  l.style = { fillColor: cfg.leafColor, closed: true };&#xA;}&#xA;function branchpart(pt, angle, width, length, cfg) {&#xA;    var wh = width/2;&#xA;    var rect = Path.Rectangle(&#xA;          pt - x*wh + y*wh,&#xA;          pt + x*wh - y*(length+wh));&#xA;    rect.style = { fillColor: cfg.treeColor };&#xA;    rect.rotate(angle, pt);&#xA;    var nextroot = (pt - y*length).rotate(angle, pt);&#xA;    return {&#xA;        rect: rect,&#xA;        next: nextroot,&#xA;    }&#xA;}&#xA;function branch(pt, angle, width, length, cfg) {&#xA;  var b = branchpart(pt, angle, width, length, cfg);&#xA;  if (width &gt; 3) {&#xA;      // Recurse&#xA;      var n = b.next;&#xA;      var area = width*width;&#xA;      var ffrac = Math.random(); // first branch fraction of area&#xA;      var sfrac = 1-ffrac;  // same for second branch&#xA;      if (ffrac &gt; 0.05) {&#xA;        var fangle = angle + (1-ffrac)*45;&#xA;        branch(n, fangle, Math.sqrt(area*ffrac), length*0.92, cfg);&#xA;      }&#xA;      if (sfrac &gt; 0.05) {&#xA;        var sangle = angle - (1-sfrac)*45;&#xA;        branch(n, sangle, Math.sqrt(area*sfrac), length*0.92, cfg);&#xA;      }&#xA;  } else {&#xA;    leaf(b.next, angle, 20, cfg);&#xA;  }&#xA;}&#xA;function tree(pt, cfg) {&#xA;  branch(pt, 0, 40, 35, cfg);&#xA;}&#xA;function threeTreeHorizontalScene() {&#xA;    var fullwidth = paper.view.size.width;&#xA;    var height = paper.view.size.height;&#xA;    var border = Math.round(fullwidth/12) + 50;&#xA;    var frame = Path.Rectangle(new Point(border, height-322), new Point(fullwidth-border, height-2));&#xA;    frame.style = {&#xA;        fillColor: &#39;white&#39;,&#xA;        strokeColor: &#39;black&#39;,&#xA;        strokeWidth: 2&#xA;    }&#xA;    var innerwidth = fullwidth - 2*border;&#xA;    if (innerwidth &gt; 320) {&#xA;        tree(new Point(border + Math.round(innerwidth*(1/3)), height-23), config(&#34;black&#34;, &#34;Orange&#34;));&#xA;        tree(new Point(border + Math.round(innerwidth*(2/3)), height-23), config(&#34;black&#34;, &#34;#ec5800&#34;));&#xA;    } else {&#xA;        tree(new Point(border + Math.round(innerwidth*(1/2)), height-23), config(&#34;black&#34;, &#34;#03992c&#34;));&#xA;    }&#xA;}&#xA;threeTreeHorizontalScene();&#xA;&lt;/script&gt;&#xA;&lt;canvas data-paper-resize=&#34;true&#34; id=&#34;trees&#34; style=&#34;width:120%; margin-left: -10%; margin-right: -10%; height: 400px;&#34;&gt;&lt;/canvas&gt;&#xA;&lt;figcaption&gt;&lt;p&gt;These trees are procedurally regenerated on every page load.&lt;/p&gt;&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;h2 id=&#34;basic-algorithm&#34;&gt;Basic algorithm&lt;/h2&gt;&#xA;&lt;p&gt;At the heart of this algorithm, there is a recursive function which&#xA;draws a tree branch (as a rotated black rectangle) and its&#xA;sub-branches.  The function calls itself recursively for the two&#xA;sub-branches, using smaller branch sizes.  When the width is finally&#xA;too small to continue for the branch we&amp;rsquo;re looking at, we draw a leaf&#xA;and stop there.&lt;/p&gt;&#xA;&lt;p&gt;To randomize the tree shape, we&amp;rsquo;re picking two weights from 0 to 1 for&#xA;the two branches, which are adding up to 1.  The weights are used to&#xA;determine the sub-branch sizes and angles.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The two sub-branches should together have the same surface area as&#xA;the parent when you saw through them. The surface area is split&#xA;according to weight.&lt;/li&gt;&#xA;&lt;li&gt;Big sub-branches (with big weight) grow straight ahead, while small&#xA;ones grow more to the side, up to 45°.&lt;/li&gt;&#xA;&lt;li&gt;Very small sub-branches with too small weights are cut off and not&#xA;drawn anymore.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;background&#34;&gt;Background&lt;/h2&gt;&#xA;&lt;p&gt;The Javascript library I&amp;rsquo;m using is &lt;a href=&#34;http://paperjs.org&#34;&gt;Paperjs&lt;/a&gt;,&#xA;which I discovered through&#xA;&lt;a href=&#34;https://media.ccc.de/v/35c3-1-generative-art-with-paper-js&#34;&gt;the PaperJS talk at 35C3&lt;/a&gt; by &lt;a href=&#34;https://bleeptrack.de&#34;&gt;bleeptrack&lt;/a&gt;.&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/trees/</guid>
      <pubDate>Wed, 23 Jan 2019 11:35:00 +0200</pubDate>
    </item>
    <item>
      <title>Internet of Things: Wifi Radio</title>
      <link>https://blog.gnoack.org/post/wifi_radio</link>
      <description>&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; This setup stopped working after a few firmware&#xA;updates; there were apparently some software updates after the&#xA;&lt;a href=&#34;https://www.heise.de/newsticker/meldung/Massenhafter-Ausfall-von-Internetradios-4417248.html&#34;&gt;catalog of internet radio stations broke down&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Maybe they also read my bug report about the broken encoding and found&#xA;my blog post. I didn&amp;rsquo;t investigate much; superficially it looked like&#xA;the radio is just ignoring the returned IP address if it&amp;rsquo;s a local&#xA;one.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Have you ever wondered what your Internet-connected devices are doing&#xA;behind your back?&lt;/p&gt;&#xA;&lt;p&gt;My internet radio had some problems with displaying special characters&#xA;in the list of radio stations. When I&#xA;&lt;a href=&#34;https://www.unix-ag.uni-kl.de/~guenther/tcpdump-fun.html&#34;&gt;checked the network traffic on Wireshark&lt;/a&gt;,&#xA;I found that the protocol for connecting back was unencrypted, so I&#xA;made it talk through a proxy which modifies the responses on the fly&#xA;to fix up wrong character encoding in the server responses.&lt;/p&gt;&#xA;&lt;p&gt;Basic setup:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The router giving out DHCP leases makes clients talk to its own local DNS service.&lt;/li&gt;&#xA;&lt;li&gt;The DNS service rewires the hostname for the radio API to the local Raspberry Pi&amp;rsquo;s IP&lt;/li&gt;&#xA;&lt;li&gt;The Raspberry Pi acts as a reverse HTTP proxy for the actual domain and modifies&#xA;requests along the way.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/images/diagram600.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;Reverse proxies are simple to write in Go: use&#xA;&lt;a href=&#34;https://golang.org/pkg/net/http/httputil/#NewSingleHostReverseProxy&#34;&gt;&lt;code&gt;httputil.NewSingleHostReverseProxy&lt;/code&gt;&lt;/a&gt;&#xA;and then set the &lt;code&gt;ReverseProxy.ModifyResponse&lt;/code&gt; property on the&#xA;returned object to an appropriate modification function such as:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;func Modify(resp *http.Response) error {&#xA;        b, err := ioutil.ReadAll(resp.Body)&#xA;        resp.Body.Close()&#xA;        if err != nil {&#xA;                return err&#xA;        }&#xA;        b = ModifyBody(b)  // Actual replacements done here.&#xA;        resp.Body = ioutil.NopCloser(bytes.NewReader(b))&#xA;        resp.ContentLength = int64(len(b))&#xA;        resp.Header.Set(&amp;quot;Content-Length&amp;quot;, strconv.Itoa(len(b)))&#xA;        return nil&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;In my implementation, I&amp;rsquo;m replacing some wrongly encoded characters&#xA;with correct ones in the server response, and for demo purposes and&#xA;some silly entertainment, I&amp;rsquo;m changing the German word for Switzerland&#xA;to &amp;ldquo;Swizzle&amp;rdquo;:&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/images/radio600.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;/figure&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/wifi_radio/</guid>
      <pubDate>Wed, 09 Jan 2019 12:05:01 +0100</pubDate>
    </item>
    <item>
      <title>Shared base fixture</title>
      <link>https://blog.gnoack.org/post/base_fixture</link>
      <description>&lt;figure&gt;&#xA;&lt;div id=&#39;pikchr-0&#39; class=&#39;pikchr&#39;&gt;&#xA;&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:537px&#39;&gt;&#xA;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 537.726 286.526&#34;&gt;&#xA;&lt;polygon points=&#34;74.16,63.2636 62.64,67.5836 62.64,58.9436&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M2.16,63.2636L68.4,63.2636&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;38.16&#34; y=&#34;51.5636&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;make&lt;/text&gt;&#xA;&lt;path d=&#34;M74.16,91.6101L159.199,91.6101L159.199,34.9172L74.16,34.9172Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;116.68&#34; y=&#34;53.1836&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;base&lt;/text&gt;&#xA;&lt;text x=&#34;116.68&#34; y=&#34;73.3436&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;case&lt;/text&gt;&#xA;&lt;polygon points=&#34;385.971,63.2636 374.451,67.5836 374.451,58.9436&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M159.199,63.2636L380.211,63.2636&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M385.971,91.6101L471.01,91.6101L471.01,34.9172L385.971,34.9172Z&#34;  style=&#34;fill:rgb(240,255,240);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;428.491&#34; y=&#34;63.2636&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;result&lt;/text&gt;&#xA;&lt;path d=&#34;M159.199,176.649L244.239,176.649L244.239,119.957L159.199,119.957Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;201.719&#34; y=&#34;138.223&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;derived&lt;/text&gt;&#xA;&lt;text x=&#34;201.719&#34; y=&#34;158.383&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;case 1&lt;/text&gt;&#xA;&lt;path d=&#34;M159.199,261.689L244.239,261.689L244.239,204.996L159.199,204.996Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;201.719&#34; y=&#34;223.262&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;derived&lt;/text&gt;&#xA;&lt;text x=&#34;201.719&#34; y=&#34;243.422&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;case 2&lt;/text&gt;&#xA;&lt;path d=&#34;M385.971,176.649L471.01,176.649L471.01,119.957L385.971,119.957Z&#34;  style=&#34;fill:rgb(240,255,240);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;428.491&#34; y=&#34;148.303&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;result&lt;/text&gt;&#xA;&lt;path d=&#34;M385.971,261.689L471.01,261.689L471.01,204.996L385.971,204.996Z&#34;  style=&#34;fill:rgb(240,255,240);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;text x=&#34;428.491&#34; y=&#34;233.342&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;result&lt;/text&gt;&#xA;&lt;polygon points=&#34;385.971,148.303 374.451,152.623 374.451,143.983&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M244.239,148.303L380.211,148.303&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;polygon points=&#34;385.971,233.342 374.451,237.662 374.451,229.022&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M244.239,233.342L380.211,233.342&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M116.68,91.6101L116.68,233.342&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;polygon points=&#34;159.199,233.342 147.679,237.662 147.679,229.022&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M116.68,233.342L153.439,233.342&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;polygon points=&#34;159.199,148.303 147.679,152.623 147.679,143.983&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;&#xA;&lt;path d=&#34;M116.68,148.303L153.439,148.303&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;&#xA;&lt;path d=&#34;M266.916,12.24L266.916,284.366&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:7.2,7.2;&#34; /&gt;&#xA;&lt;path d=&#34;M363.294,12.24L363.294,284.366&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:7.2,7.2;&#34; /&gt;&#xA;&lt;text x=&#34;507.861&#34; y=&#34;43.1036&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;expect&lt;/text&gt;&#xA;&lt;text x=&#34;507.861&#34; y=&#34;63.2636&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;happy&lt;/text&gt;&#xA;&lt;text x=&#34;507.861&#34; y=&#34;83.4236&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;case&lt;/text&gt;&#xA;&lt;text x=&#34;507.861&#34; y=&#34;128.143&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;expect&lt;/text&gt;&#xA;&lt;text x=&#34;507.861&#34; y=&#34;148.303&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;corner&lt;/text&gt;&#xA;&lt;text x=&#34;507.861&#34; y=&#34;168.463&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;case 1&lt;/text&gt;&#xA;&lt;text x=&#34;507.861&#34; y=&#34;213.182&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;expect&lt;/text&gt;&#xA;&lt;text x=&#34;507.861&#34; y=&#34;233.342&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;corner&lt;/text&gt;&#xA;&lt;text x=&#34;507.861&#34; y=&#34;253.502&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;case 2&lt;/text&gt;&#xA;&lt;text x=&#34;201.719&#34; y=&#34;12.24&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;set up&lt;/text&gt;&#xA;&lt;text x=&#34;428.491&#34; y=&#34;12.24&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;verify result&lt;/text&gt;&#xA;&lt;text x=&#34;315.105&#34; y=&#34;12.24&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;exercise&lt;/text&gt;&#xA;&lt;text x=&#34;116.68&#34; y=&#34;152.396&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; transform=&#34;rotate(-90 116.68,162.476)&#34; dominant-baseline=&#34;central&#34;&gt;modify&lt;/text&gt;&#xA;&lt;/svg&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;figcaption&gt;A diagram of how different tests share common test setup with a shared base fixture&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;&lt;strong&gt;Q&lt;/strong&gt;: How do you know you can trust your test set-up?&lt;br&gt;&#xA;&lt;strong&gt;A&lt;/strong&gt;: You reuse a well-known test set up in every test.&lt;/p&gt;&#xA;&lt;h2 id=&#34;example-code&#34;&gt;Example code&lt;/h2&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def test_simple():&#xA;  req = set_up_working_request()&#xA;  resp = invoke(req)&#xA;  assert resp.status == OK&#xA;&#xA;def test_invalid_page_size():&#xA;  req = set_up_working_request()&#xA;  req.page_size = -5&#xA;  resp = invoke(req)&#xA;  assert resp.status == INVALID_ARGUMENT&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;In the test,&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;We call &lt;code&gt;set_up_working_request()&lt;/code&gt; and we know this results in&#xA;&amp;ldquo;working&amp;rdquo; behavior.  Then we purposefully inject a defective&#xA;negative page size into the working request.&lt;/li&gt;&#xA;&lt;li&gt;We exercise the system under test in the same way.&lt;/li&gt;&#xA;&lt;li&gt;We expect a different result.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Because the only difference in set up between &lt;code&gt;test_simple&lt;/code&gt; and&#xA;&lt;code&gt;test_invalid_page_size&lt;/code&gt; was in the differing page size, we can easily&#xA;reason that the different response status is resulting from just that.&lt;/p&gt;&#xA;&lt;h2 id=&#34;related-techniques&#34;&gt;Related techniques&lt;/h2&gt;&#xA;&lt;p&gt;This works well together with these techniques:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Structure your test methods with &lt;strong&gt;separate set up, exercise and&#xA;verify phases&lt;/strong&gt;.&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;&#xA;&lt;li&gt;Use &lt;strong&gt;explicit helper functions for set up&lt;/strong&gt; and possibly name them&#xA;according to expected behavior such as &amp;ldquo;working&amp;rdquo; in the example&#xA;above.&lt;/li&gt;&#xA;&lt;li&gt;Keep the shared &lt;strong&gt;set up code in test methods as short as&#xA;possible&lt;/strong&gt;, so that it&amp;rsquo;s easy to spot the equal parts.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;1:N&lt;/strong&gt;: Use one base scenario (e.g. &amp;ldquo;working&amp;rdquo;) and use its set up&#xA;as a base for multiple derived scenarios.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;This is called the &amp;ldquo;Four-Phase test&amp;rdquo; in the xUnit&#xA;test pattern book. (&lt;a href=&#34;https://martinfowler.com/books/meszaros.html&#34;&gt;Meszaros07, p358&lt;/a&gt;)&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/base_fixture/</guid>
      <pubDate>Tue, 06 Nov 2018 07:44:44 +0100</pubDate>
    </item>
    <item>
      <title>No error left behind</title>
      <link>https://blog.gnoack.org/post/error_handling</link>
      <description>&lt;figure&gt;&#xA;&lt;img src=&#34;/images/reliability.svg&#34; alt=&#34;Cartoon in the style of webcomicname.com - first panel: Stakeholder: &amp;lsquo;Make it do X&amp;rsquo; Developer: &amp;lsquo;OK&amp;rsquo;; second panel: developer works on machine, thinks: &amp;lsquo;X X X X X&amp;rsquo;; third panel: user uses the machine saying &amp;lsquo;Y&amp;rsquo;. Machine: explodes. Developer: &amp;lsquo;oh no&amp;rsquo;&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;Which design guidelines should software follow in order to run&#xA;reliably?  Which guidelines do you use in your day-to-day work?&lt;/p&gt;&#xA;&lt;p&gt;Error handling is a significant complexity in real-world projects, but&#xA;programming textbooks are often giving very little advice on how to&#xA;think about it at the higher level.  This article tries to fill that&#xA;gap:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;We will define what an error is.&lt;/li&gt;&#xA;&lt;li&gt;We will find out that each error has a human stakeholder.&lt;/li&gt;&#xA;&lt;li&gt;We will discuss technical mechanisms to bring errors to human attention.&lt;/li&gt;&#xA;&lt;li&gt;The final section contains various examples of how to apply this.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;To handle the error cases in your software, you should ask yourself&#xA;who is the human stakeholder who would be able to address it, and then&#xA;find a suitable mechanism to escalate the error in the direction of&#xA;that stakeholder.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;ve cross-checked this approach with multiple people from various&#xA;software backgrounds, but I&amp;rsquo;m still happy to receive your feedback.&lt;/p&gt;&#xA;&lt;h1 id=&#34;what-is-an-error&#34;&gt;What is an error?&lt;/h1&gt;&#xA;&lt;blockquote class=&#34;def&#34;&gt;&lt;p&gt;&lt;strong&gt;Definition:&lt;/strong&gt;&#xA;&lt;em&gt;An error&lt;/em&gt; is when the program is operating outside the intended path&#xA;of execution.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Running programs within the intended path of execution is a goal by&#xA;definition.  To track and reach this goal, we need to make it&#xA;observable whether the program is running healthily:&lt;/p&gt;&#xA;&lt;blockquote class=&#34;rule&#34;&gt;&lt;p&gt;&lt;strong&gt;Rule:&lt;/strong&gt;&#xA;All errors should be &lt;em&gt;observable&lt;/em&gt; from &lt;em&gt;the outside&lt;/em&gt;.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;&lt;em&gt;Observable&lt;/em&gt; in this context means that it&amp;rsquo;s possible to bring the&#xA;error to a human&amp;rsquo;s attention (e.g. end user, system administrator,&#xA;developer) in an automated fashion.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;The outside&lt;/em&gt; is defined by the bounds of your program.  The error&#xA;reports need to be made accessible to the surrounding environment,&#xA;so that stakeholders can access them.&lt;/p&gt;&#xA;&lt;h2 id=&#34;error-stakeholders&#34;&gt;Error stakeholders&lt;/h2&gt;&#xA;&lt;p&gt;The stakeholders for an error are the people involved in the software&#xA;lifecycle, such as: End users, developers, system administrators,&#xA;network administrators etc.&lt;/p&gt;&#xA;&lt;blockquote class=&#34;rule&#34;&gt;&lt;p&gt;&lt;strong&gt;Rule:&lt;/strong&gt;&#xA;For each error, there is a corresponding stakeholder.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/images/stakeholders.svg&#34; alt=&#34;&#34;&gt;&#xA;&lt;figcaption&gt;&lt;p&gt;Different errors have different stakeholders who can address the issue.&lt;/p&gt;&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;Is the error cause &lt;strong&gt;within the program itself&lt;/strong&gt;, then the&#xA;&lt;strong&gt;developer&lt;/strong&gt; is the stakeholder.&lt;/p&gt;&#xA;&lt;p&gt;Is the error cause &lt;strong&gt;in the user input or interaction&lt;/strong&gt; (e.g. invalid&#xA;input), then &lt;strong&gt;the user&lt;/strong&gt; is the stakeholder.&lt;/p&gt;&#xA;&lt;p&gt;Is the error cause &lt;strong&gt;in the execution environment&lt;/strong&gt;, then &lt;strong&gt;the&#xA;operator of that environment&lt;/strong&gt; is the stakeholder (e.g. sysadmin,&#xA;network admin, SRE).&lt;/p&gt;&#xA;&lt;h1 id=&#34;mechanisms&#34;&gt;Mechanisms&lt;/h1&gt;&#xA;&lt;h2 id=&#34;routing-errors-to-the-stakeholders&#34;&gt;Routing errors to the stakeholders&lt;/h2&gt;&#xA;&lt;p&gt;Routing error indicators to the right stakeholders is partially done&#xA;in code, and partially within the deployment.  Particularly,&#xA;displaying errors to end users is usually done in the program code&#xA;itself.  On the other hand, metrics collection set-ups can be&#xA;monitored by developers and administrators alike.&lt;/p&gt;&#xA;&lt;p&gt;There are two main strategies to make errors observable:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Propagate the error upwards towards the initiator of the erroring&#xA;operation.&lt;/li&gt;&#xA;&lt;li&gt;Propagate the error to the side (monitoring and logging).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;At least one of these should be used for any error.&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/images/errors.svg&#34; alt=&#34;&#34;&gt;&#xA;&lt;figcaption&gt;&lt;p&gt;A function can propagate errors upwards or to the side,&lt;br&gt;at least one of these should be used.&lt;/p&gt;&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;h2 id=&#34;propagating-an-error-upwards&#34;&gt;Propagating an error upwards&lt;/h2&gt;&#xA;&lt;p&gt;Propagating &amp;ldquo;upwards&amp;rdquo; moves the responsibility of error handling to a&#xA;higher level.  In general, higher level software has more context for&#xA;the failing operation, so they are often in a better position to route&#xA;the error in the right direction.&lt;/p&gt;&#xA;&lt;p&gt;Propagating errors upwards can take many forms.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Function level: &lt;strong&gt;Propagate to the calling procedure&lt;/strong&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Return an error code&lt;/li&gt;&#xA;&lt;li&gt;Raise an exception&lt;/li&gt;&#xA;&lt;li&gt;Propagate a lower-level exception&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Process level: &lt;strong&gt;Crash the process&lt;/strong&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Exit the program with an error status (e.g. Unix &lt;a href=&#34;http://man7.org/linux/man-pages/man3/exit.3.html&#34;&gt;&lt;code&gt;exit()&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;&#xA;&lt;li&gt;Abort the program (e.g. Unix &lt;a href=&#34;http://man7.org/linux/man-pages/man3/abort.3.html&#34;&gt;&lt;code&gt;abort()&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Network level: &lt;strong&gt;Return the error in a network response&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;User level: &lt;strong&gt;Show the error to the user&lt;/strong&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;e.g. in a UI dialog&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&#xA;Remember to convert the error into a representation which fits the&#xA;level of abstraction that the caller expects.  Many languages&#xA;support nesting (wrapping) errors so that the full context is&#xA;retained.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h2 id=&#34;propagating-an-error-to-the-side&#34;&gt;Propagating an error to the side&lt;/h2&gt;&#xA;&lt;p&gt;Sometimes passing the error upwards is not an option or not&#xA;sufficient, for example because you want to transparently recover or&#xA;hide a subsystem failure from the user.&lt;/p&gt;&#xA;&lt;p&gt;Propagating errors to the side can be one of the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Increment a counter which can be monitored from the outside.&#xA;(e.g. using Prometheus or Linux kernel stats counters)&lt;/li&gt;&#xA;&lt;li&gt;Write the error to an error collection service.&#xA;&lt;ul&gt;&#xA;&lt;li&gt;For server side software: Record stack traces and notify&#xA;developers about them.&lt;/li&gt;&#xA;&lt;li&gt;For client side software: Ask the user to send bug reports when&#xA;errors are encountered.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Make sure that all the relevant error propagation sinks are&#xA;monitored by the right stakeholders during the program&amp;rsquo;s operation.&lt;/p&gt;&#xA;&lt;p&gt;Systems like Prometheus are built with monitoring and alerting in&#xA;mind.  It&amp;rsquo;s often a good idea to alert on symptoms close to your&#xA;business needs and then use collected metrics on other errors for&#xA;further analysis&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;&#xA;&lt;blockquote class=&#34;warning&#34;&gt;&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt;&#xA;Textual logging is not an error handling strategy. Logs are not&#xA;meant for machine consumption, so it&amp;rsquo;s hard to have automated&#xA;monitoring based on them.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;blockquote class=&#34;warning&#34;&gt;&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt;&#xA;Ignoring errors is not an error handling strategy either.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h2 id=&#34;what-if-my-case-is-not-a-fit&#34;&gt;What if my case is not a fit?&lt;/h2&gt;&#xA;&lt;p&gt;If your case it not a fit, it&amp;rsquo;s possible that the condition at hand&#xA;might not be an error to begin with, but is maybe only a &amp;ldquo;corner case&amp;rdquo;&#xA;which may happen in normal operation (e.g. a lookup key was not&#xA;found).&lt;/p&gt;&#xA;&lt;p&gt;Consider switching the way that the condition is propagated.  The&#xA;following options are alternatives where otherwise errors may be&#xA;used.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Null/empty object:&lt;/strong&gt; Returning empty lists, sets, &lt;code&gt;Optional&amp;lt;T&amp;gt;&lt;/code&gt;&#xA;types, or other &lt;a href=&#34;https://en.wikipedia.org/wiki/Null_object_pattern&#34;&gt;Null&#xA;Objects&lt;/a&gt;. Note&#xA;that this is not the same as &lt;code&gt;null&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Separate channel:&lt;/strong&gt; Return the non-error conditions through a&#xA;separate channel (e.g. don&amp;rsquo;t use an exception, but return&#xA;specially-built objects for these conditions).  &lt;strong&gt;Example:&lt;/strong&gt; A&#xA;linter tool&amp;rsquo;s output is produced as part of the expected operation&#xA;and is therefore not an error within that context.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Null:&lt;/strong&gt; Returning &lt;code&gt;null&lt;/code&gt;, &lt;code&gt;nil&lt;/code&gt; or similar is idiomatic in some languages&#xA;too, but may lead to follow-up&#xA;errors&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&#xA;when the value is dereferenced.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;If none of these worked for you, I&amp;rsquo;d love to hear from you,&#xA;so I can correct my understanding.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Sometimes the most elegant solution is to &lt;strong&gt;change the API to make the&#xA;error impossible&lt;/strong&gt;&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;. For example, replace a dynamic check with&#xA;one that&amp;rsquo;s statically guaranteed by the type system, or change to&#xA;idempotent operation semantics, so that multiple invocations do not&#xA;conflict with each other.&lt;/p&gt;&#xA;&lt;h1 id=&#34;examples&#34;&gt;Examples&lt;/h1&gt;&#xA;&lt;p&gt;These are all written from the perspective of a piece of code&#xA;detecting an error.&lt;/p&gt;&#xA;&lt;h2 id=&#34;recovery-through-redundancy&#34;&gt;Recovery through redundancy&lt;/h2&gt;&#xA;&lt;h3 id=&#34;example&#34;&gt;Example&lt;/h3&gt;&#xA;&lt;p&gt;A disk in a software RAID is failing.&lt;/p&gt;&#xA;&lt;h3 id=&#34;stakeholder&#34;&gt;Stakeholder&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;The system administrator&lt;/strong&gt;, as soon as the percentage of recovered executions &amp;gt; threshold.&#xA;They can then investigate the cause of network issues, exchange hard&#xA;drives or similar.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;mechanism&#34;&gt;Mechanism&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Recover&lt;/strong&gt; by retrying the operation on a different disk.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Increment an error counter&lt;/strong&gt; indicating the failure cause.  When&#xA;incremented in a monitorable system, this counter can trigger an alert.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;similar-cases&#34;&gt;Similar cases&lt;/h3&gt;&#xA;&lt;p&gt;A TCP network packet is lost. (Difference: Retry has less control over&#xA;the network routing)&lt;/p&gt;&#xA;&lt;h2 id=&#34;recovery-through-omission&#34;&gt;Recovery through omission&lt;/h2&gt;&#xA;&lt;h3 id=&#34;example-1&#34;&gt;Example&lt;/h3&gt;&#xA;&lt;p&gt;A web server uses multiple database backends.  One of the&#xA;non-essential backends starts to return errors.&lt;/p&gt;&#xA;&lt;h3 id=&#34;stakeholder-1&#34;&gt;Stakeholder&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The &lt;strong&gt;operator&lt;/strong&gt; of the failing subsystem.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;mechanism-1&#34;&gt;Mechanism&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Omit&lt;/strong&gt; the backend&amp;rsquo;s response.  (Treat it as if it didn&amp;rsquo;t exist.)&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Increment an error counter&lt;/strong&gt; indicating the failure cause, so that&#xA;the subsystem operator can be alerted.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;delegating-the-decision-to-the-calling-procedure&#34;&gt;Delegating the decision to the calling procedure&lt;/h2&gt;&#xA;&lt;h3 id=&#34;example-2&#34;&gt;Example&lt;/h3&gt;&#xA;&lt;p&gt;The Unix &lt;code&gt;open()&lt;/code&gt; function is asked to open a given filename for&#xA;reading, but the file doesn&amp;rsquo;t exist.&lt;/p&gt;&#xA;&lt;h3 id=&#34;stakeholder-2&#34;&gt;Stakeholder&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;We don&amp;rsquo;t know&lt;/strong&gt; who is responsible for passing the wrong filename,&#xA;but somewhere in the call chain, someone is going to know where that&#xA;filename comes from.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;mechanism-2&#34;&gt;Mechanism&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Report the error to the caller&lt;/strong&gt; with the documented &lt;code&gt;ENOENT&lt;/code&gt; error code.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;similar-cases-1&#34;&gt;Similar cases&lt;/h3&gt;&#xA;&lt;p&gt;Mistakes in passed input values are best handled by the code which&#xA;passed them, and which can judge why they happened.&lt;/p&gt;&#xA;&lt;h2 id=&#34;reporting-upwards-and-sideways-at-the-same-time&#34;&gt;Reporting upwards and sideways at the same time&lt;/h2&gt;&#xA;&lt;h3 id=&#34;example-3&#34;&gt;Example&lt;/h3&gt;&#xA;&lt;p&gt;A web server&amp;rsquo;s servlets are returning errors in the form of HTTP&#xA;status codes.&lt;/p&gt;&#xA;&lt;h3 id=&#34;stakeholders&#34;&gt;Stakeholders&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The &lt;strong&gt;requester&lt;/strong&gt; is a stakeholder because they care about the&#xA;request.&lt;/li&gt;&#xA;&lt;li&gt;The web server&amp;rsquo;s &lt;strong&gt;operator&lt;/strong&gt; is a stakeholder because they care&#xA;about keeping overall error fractions within reasonable bounds.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;mechanisms-1&#34;&gt;Mechanisms&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Propagate status via HTTP&lt;/strong&gt;, upwards to the caller who has more&#xA;context.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Count HTTP statuses&lt;/strong&gt; keyed by relevant criteria (such as&#xA;servlet), e.g. in Prometheus, for the web server operator.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;A good background read is the &lt;a href=&#34;https://landing.google.com/sre/book/chapters/monitoring-distributed-systems.html#symptoms-versus-causes-g0sEi4&#34;&gt;Site Reliability Engineering Book&lt;/a&gt;, section &amp;ldquo;Symptoms vs. Causes&amp;rdquo;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Tony_Hoare#Apologies_and_retractions&#34;&gt;Wikipedia: Tony Hoare, section &amp;ldquo;Apologies and retractions&amp;rdquo;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:3&#34;&gt;&#xA;&lt;p&gt;The book &lt;a href=&#34;https://www.goodreads.com/book/show/39996759-a-philosophy-of-software-design&#34;&gt;Philosophy of Software Design&lt;/a&gt; by John Ousterhout has an entire chapter on the idea of defining errors away.  The author has also given a &lt;a href=&#34;https://www.youtube.com/watch?v=bmSAYlu0NcYt&#34;&gt;tech talk&lt;/a&gt;.&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/error_handling/</guid>
      <pubDate>Mon, 03 Sep 2018 22:36:41 +0200</pubDate>
    </item>
    <item>
      <title>There are my core dumps!</title>
      <link>https://blog.gnoack.org/post/there-are-my-core-dumps</link>
      <description>&lt;p&gt;&lt;a href=&#34;https://www.unix-ag.uni-kl.de/~guenther/where-are-my-core-dumps.html&#34;&gt;As noted&#xA;before&lt;/a&gt;,&#xA;with &lt;code&gt;systemd&lt;/code&gt;, your core dumps disappear into one of &lt;code&gt;systemd&lt;/code&gt;&amp;rsquo;s log&#xA;sinks, instead of being stored to the current directory. By now, they&#xA;are recoverable by normal users again.&lt;/p&gt;&#xA;&lt;p&gt;TL;DR: Run &lt;code&gt;coredumpctl gdb&lt;/code&gt; to invoke &lt;code&gt;gdb&lt;/code&gt; with the most recent core dump.&lt;/p&gt;&#xA;&lt;p&gt;Related bug about disappearing coredumps:&#xA;&lt;a href=&#34;https://bugs.freedesktop.org/show_bug.cgi?id=54288&#34;&gt;https://bugs.freedesktop.org/show_bug.cgi?id=54288&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;Scenario: A simple program that crashes with a segfault:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;~/dumpcore$ cat dumpcore.c&#xA;#include &amp;lt;unistd.h&amp;gt;&#xA;void dump_core()   { int* boom = NULL; *boom = 2000; }&#xA;void its_time_to() { dump_core(); }&#xA;int main()         { its_time_to(); }&#xA;~/dumpcore$ cc -g -o dumpcore dumpcore.c&#xA;~/dumpcore$ ./dumpcore&#xA;Segmentation fault (core dumped)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Core dumps get written to &lt;code&gt;systemd&lt;/code&gt;&amp;rsquo;s core dumps directory (see &lt;code&gt;man coredumpctl&lt;/code&gt;), and can be retrieved with the &lt;code&gt;coredumpctl&lt;/code&gt; tool:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;~/dumpcore$ coredumpctl list&#xA;TIME                            PID   UID   GID SIG PRESENT EXE&#xA;...&#xA;Sun 2016-10-02 14:44:14 CEST   3857  1000   100  11 * /home/me/dumpcore/dumpcore&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;By default, &lt;code&gt;coredumpctl&lt;/code&gt; seems to use the most recent core dump,&#xA;so that you can easily inspect the most recent core dump with:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;~/dumpcore$ coredumpctl gdb&#xA;           PID: 3857 (dumpcore)&#xA;           UID: 1000 (me)&#xA;           GID: 100 (users)&#xA;        Signal: 11 (SEGV)&#xA;     Timestamp: Sun 2016-10-02 14:44:14 CEST (1min 3s ago)&#xA;  Command Line: ./dumpcore&#xA;    Executable: /home/me/dumpcore/dumpcore&#xA; Control Group: /user.slice/user-1000.slice/user@1000.service/gnome-terminal-server.service&#xA;          Unit: user@1000.service&#xA;     User Unit: user@1000.service&#xA;         Slice: user-1000.slice&#xA;     Owner UID: 1000 (me)&#xA;       Boot ID: 73902fbce4e241f5bab007aad96895eb&#xA;    Machine ID: 3ff4d30a94914397acd6af26eed15114&#xA;      Hostname: limbo&#xA;      Coredump: /var/lib/systemd/coredump/core.dumpcore.1000.73902fbce4e241f5bab007aad96895eb.3857.1475412254000000000000.lz4&#xA;       Message: Process 3857 (dumpcore) of user 1000 dumped core.&#xA;&#xA;                Stack trace of thread 3857:&#xA;                #0  0x00000000004004b6 dump_core (dumpcore)&#xA;                #1  0x00000000004004cd its_time_to (dumpcore)&#xA;                #2  0x00000000004004de main (dumpcore)&#xA;                #3  0x00007f89ba351291 __libc_start_main (libc.so.6)&#xA;                #4  0x00000000004003da _start (dumpcore)&#xA;&#xA;GNU gdb (GDB) 7.11.1&#xA;Copyright (C) 2016 Free Software Foundation, Inc.&#xA;License GPLv3+: GNU GPL version 3 or later &amp;lt;http://gnu.org/licenses/gpl.html&amp;gt;&#xA;This is free software: you are free to change and redistribute it.&#xA;There is NO WARRANTY, to the extent permitted by law.  Type &amp;quot;show copying&amp;quot;&#xA;and &amp;quot;show warranty&amp;quot; for details.&#xA;This GDB was configured as &amp;quot;x86_64-pc-linux-gnu&amp;quot;.&#xA;Type &amp;quot;show configuration&amp;quot; for configuration details.&#xA;For bug reporting instructions, please see:&#xA;&amp;lt;http://www.gnu.org/software/gdb/bugs/&amp;gt;.&#xA;Find the GDB manual and other documentation resources online at:&#xA;&amp;lt;http://www.gnu.org/software/gdb/documentation/&amp;gt;.&#xA;For help, type &amp;quot;help&amp;quot;.&#xA;Type &amp;quot;apropos word&amp;quot; to search for commands related to &amp;quot;word&amp;quot;...&#xA;Reading symbols from /home/me/dumpcore/dumpcore...done.&#xA;[New LWP 3857]&#xA;&#xA;warning: Could not load shared library symbols for linux-vdso.so.1.&#xA;Do you need &amp;quot;set solib-search-path&amp;quot; or &amp;quot;set sysroot&amp;quot;?&#xA;Core was generated by `./dumpcore&#39;.&#xA;Program terminated with signal SIGSEGV, Segmentation fault.&#xA;#0  0x00000000004004b6 in dump_core () at dumpcore.c:2&#xA;2&#x9;void dump_core()   { int* boom = NULL; *boom = 2000; }&#xA;(gdb) bt&#xA;#0  0x00000000004004b6 in dump_core () at dumpcore.c:2&#xA;#1  0x00000000004004cd in its_time_to () at dumpcore.c:3&#xA;#2  0x00000000004004de in main () at dumpcore.c:4&#xA;(gdb)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/there-are-my-core-dumps/</guid>
      <pubDate>Sun, 02 Oct 2016 16:45:00 +0100</pubDate>
    </item>
    <item>
      <title>GPG with the CCID Driver</title>
      <link>https://blog.gnoack.org/post/gpg-ccid</link>
      <description>&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;&lt;strong&gt;Remark&lt;/strong&gt;: I have not had this problem in years, and it&amp;rsquo;s probably long resolved.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Unless you&amp;rsquo;re using Debian, where people care about this, chances are&#xA;that setting up GPG Smartcards with your Linux distribution is an&#xA;adventure.  There are two ways to do it, CCID and PCSCLite, the latter&#xA;of which runs a background service &lt;code&gt;pcscd&lt;/code&gt; &amp;ndash; as root, at least on Arch,&#xA;while GnuPG&amp;rsquo;s built-in CCID driver accesses the reader directly&#xA;through the USB device, but took me a lot longer to figure out how to&#xA;use.&lt;/p&gt;&#xA;&lt;h2 id=&#34;problem&#34;&gt;Problem&lt;/h2&gt;&#xA;&lt;p&gt;You&amp;rsquo;re getting a &amp;ldquo;card error&amp;rdquo; when trying to access the card.  The&#xA;same thing works as root.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ gpg --card-status&#xA;gpg: selecting openpgp failed: Card error&#xA;gpg: OpenPGP card not available: Card error&#xA;$&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;When trying the same as root, you can access the card.&lt;/p&gt;&#xA;&lt;h2 id=&#34;solution&#34;&gt;Solution&lt;/h2&gt;&#xA;&lt;p&gt;Add a &lt;code&gt;udev&lt;/code&gt; rule that changes file permissions for you, as documented on&#xA;&lt;a href=&#34;https://wiki.archlinux.org/index.php/GnuPG#Smartcard_not_detected&#34;&gt;https://wiki.archlinux.org/index.php/GnuPG#Smartcard_not_detected&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;Add your user to a new user group that can read smartcards, and give&#xA;that group read-write access to the device when it&amp;rsquo;s plugged in, by&#xA;creating a file &lt;code&gt;/etc/udev/rules.d&lt;/code&gt; with the rule:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-txt&#34;&gt;ACTION==&amp;quot;add&amp;quot;, SUBSYSTEM==&amp;quot;usb&amp;quot;, ENV{ID_VENDOR_ID}==&amp;quot;08e6&amp;quot;, ENV{ID_MODEL_ID}==&amp;quot;3438&amp;quot;, MODE=&amp;quot;660&amp;quot;, GROUP=&amp;quot;scard&amp;quot;&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;(Figure out the values for the vendor and model ID using &lt;code&gt;lsusb&lt;/code&gt;, they are printed separated with a colon.)&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/gpg-ccid/</guid>
      <pubDate>Mon, 15 Aug 2016 12:00:00 +0100</pubDate>
    </item>
    <item>
      <title>Hexiamonds</title>
      <link>https://blog.gnoack.org/post/hexiamonds</link>
      <description>&lt;p&gt;I made 3D models for Hexiamond puzzle pieces, which can be &lt;a href=&#34;https://www.unix-ag.uni-kl.de/~guenther/downloads/hexiamonds.tar.gz&#34;&gt;downloaded here&lt;/a&gt; (STL format).&lt;/p&gt;&#xA;&lt;p&gt;Each Hexiamond piece consists of 6 triangles, which yields 12&#xA;different pieces when you try out all combinations.&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/images/hexiamond.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;figcaption&gt;&lt;p&gt;3d model of a Hexiamond&lt;/p&gt;&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;More background information and some interesting puzzles to try can be&#xA;found on this nice page by David Goodger:&#xA;&lt;a href=&#34;http://puzzler.sourceforge.net/docs/hexiamonds.html&#34;&gt;http://puzzler.sourceforge.net/docs/hexiamonds.html&lt;/a&gt;&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/hexiamonds/</guid>
      <pubDate>Sun, 05 Jun 2016 12:00:00 +0100</pubDate>
    </item>
    <item>
      <title>Python-like generator functions</title>
      <link>https://blog.gnoack.org/post/generators</link>
      <description>&lt;p&gt;Python-like generator functions, implemented as a library:&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;/images/fn-generators.png&#34; alt=&#34;&#34;&gt;&#xA;&lt;figcaption&gt;&lt;p&gt;Generator functions implemented as a library&lt;/p&gt;&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;This is possible through two simple tricks:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;The language represents stack frames as objects on the heap.&lt;/li&gt;&#xA;&lt;li&gt;There&amp;rsquo;s a native function for grabbing the current stack frame.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Turns out replacing the calling stack frame is really the only thing&#xA;you need in order to implement coroutines and generics.&lt;/p&gt;&#xA;&lt;p&gt;The implementation is only 23 lines long.  On my screen, including the&#xA;screenshot, this weblog article is already longer up until here.&lt;/p&gt;&#xA;</description>
      <guid>https://blog.gnoack.org/post/generators/</guid>
      <pubDate>Sun, 16 Nov 2014 19:41:00 +0100</pubDate>
    </item>
  </channel>
</rss>