<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>blog.gnoack.org</title>
    <link>https://blog.gnoack.org/</link>
    <description>Recent content on blog.gnoack.org</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Mon, 19 Feb 2024 20:45:12 +0100</lastBuildDate>
    
        <atom:link href="https://blog.gnoack.org/index.xml" rel="self" type="application/rss+xml" />
    
    
    <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>
      <pubDate>Mon, 19 Feb 2024 20:45:12 +0100</pubDate>
      
      <guid>https://blog.gnoack.org/post/proc-fd-is-not-dup/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
&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;em&gt;dup&lt;/em&gt;(2), or by passing them across process boundaries using &lt;em&gt;fork&lt;/em&gt;(2) or UNIX Domain Sockets (&lt;em&gt;unix&lt;/em&gt;(7)).&lt;/p&gt;
&lt;div id=&#39;pikchr-0&#39; class=&#39;pikchr&#39;&gt;
&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:503px&#39;&gt;
&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 503.785 218.52&#34;&gt;
&lt;path d=&#34;M2,63L110,63L110,27L2,27Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;56&#34; y=&#34;45&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;0&lt;/text&gt;
&lt;path d=&#34;M2,99L110,99L110,63L2,63Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;56&#34; y=&#34;81&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;1&lt;/text&gt;
&lt;path d=&#34;M2,135L110,135L110,99L2,99Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;56&#34; y=&#34;117&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;2&lt;/text&gt;
&lt;path d=&#34;M2,171L110,171L110,135L2,135Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;56&#34; y=&#34;153&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;3&lt;/text&gt;
&lt;path d=&#34;M393,63L501,63L501,27L393,27Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;447&#34; y=&#34;45&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;0&lt;/text&gt;
&lt;path d=&#34;M393,99L501,99L501,63L393,63Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;447&#34; y=&#34;81&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;1&lt;/text&gt;
&lt;path d=&#34;M393,135L501,135L501,99L393,99Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;447&#34; y=&#34;117&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;2&lt;/text&gt;
&lt;path d=&#34;M393,171L501,171L501,135L393,135Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;447&#34; y=&#34;153&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;3&lt;/text&gt;
&lt;text x=&#34;2&#34; y=&#34;12&#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;
&lt;text x=&#34;393&#34; y=&#34;12&#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;
&lt;path d=&#34;M197,180L305,180L305,126L197,126Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;251&#34; y=&#34;143&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;file&lt;/text&gt;
&lt;text x=&#34;251&#34; y=&#34;163&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;description&lt;/text&gt;
&lt;path d=&#34;M197,216L305,216L305,180L197,180Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;251&#34; y=&#34;198&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;f_pos&lt;/text&gt;
&lt;polygon points=&#34;197,153 186,157 186,149&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M110,153L192,153&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;
&lt;polygon points=&#34;305,153 317,149 317,157&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M393,153L311,153&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;
&lt;/svg&gt;
&lt;/div&gt;
&lt;/div&gt;
&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;
&lt;h3 id=&#34;this-feature-is-mis-documented&#34;&gt;This feature is mis-documented&lt;/h3&gt;
&lt;p&gt;The misunderstanding is even documented in my earlier edition of
&amp;ldquo;&lt;a href=&#34;https://man7.org/tlpi/&#34;&gt;The Linux Programming Interface&lt;/a&gt;&amp;rdquo; (section 5.11)
(&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;,
as Michael Kerrisk points out in the comments below):&lt;/p&gt;
&lt;blockquote&gt;
&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;
&lt;pre&gt;&lt;code class=&#34;language-bad&#34;&gt;fd = open(&amp;quot;/dev/fd/1&amp;quot;, O_WRONLY);
fd = dup(1);
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a reasonably simple explanation which is close enough to
reality for many practical use cases, and which is true on other
Unixes, but it is not fully accurate on Linux.  (The book is very
comprehensive and useful nevertheless.)&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://bugzilla.redhat.com/show_bug.cgi?id=10417&#34;&gt;This RedHat bug from
2000&lt;/a&gt; discusses how
that behaviour was apparently changed in Linux 1.3.34.  The
aforementioned equivalence between the &lt;em&gt;open&lt;/em&gt;(2) and &lt;em&gt;dup&lt;/em&gt;(2) calls is
called the &amp;ldquo;Plan9 semantics&amp;rdquo; there.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://mirrors.edge.kernel.org/pub/linux/docs/man-pages/book/man-pages-6.06.pdf#page=2246&#34;&gt;man page&lt;/a&gt;
gives usage examples, but does not go into a lot of detail on the
exact semantics in the case of &lt;em&gt;open&lt;/em&gt;(2).&lt;/p&gt;
&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;
&lt;p&gt;On top of that, the behavior is implemented differently on other Unixes.&lt;/p&gt;
&lt;p&gt;From a FreeBSD 14 box:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ./dup -dup &amp;gt; out; cat out; echo
1d
$ ./dup -proc &amp;gt; out; cat out; echo
1d
&lt;/code&gt;&lt;/pre&gt;
&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;
&lt;h2 id=&#34;part-1-an-experiment&#34;&gt;Part 1: An experiment!&lt;/h2&gt;
&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; 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;
&lt;p&gt;You can try it out with the following program:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ cat dup.c
#include &amp;lt;err.h&amp;gt;
#include &amp;lt;fcntl.h&amp;gt;
#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;

int usage(const char *name) {
  printf(&amp;quot;Usage: %s [-dup|-proc]\n&amp;quot;, name);
  return 0;
}

int main(int argc, char *argv[]) {
  int fd;

  if (argc != 2) {
    return usage(argv[0]);
  }

  if (!strcmp(argv[1], &amp;quot;-dup&amp;quot;)) {
    fd = dup(1);  // stdout
    if (fd &amp;lt; 0) {
      err(1, &amp;quot;dup&amp;quot;);
    }
  } else if (!strcmp(argv[1], &amp;quot;-proc&amp;quot;)) {
    fd = open(&amp;quot;/dev/fd/1&amp;quot;, O_WRONLY);
    if (fd &amp;lt; 0) {
      err(1, &amp;quot;open /dev/fd/1&amp;quot;);
    }
  } else {
    return usage(argv[0]);
  }

  write(1, &amp;quot;1&amp;quot;, 1);
  
  write(fd, &amp;quot;d&amp;quot;, 1);
  close(fd);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we build and run this program, we can see that the behavior of &lt;em&gt;dup&lt;/em&gt;(2) and &lt;em&gt;open&lt;/em&gt;(2) is actually different!&lt;/p&gt;
&lt;h3 id=&#34;duplicating-the-file-descriptor-using-dup2&#34;&gt;Duplicating the file descriptor using &lt;em&gt;dup&lt;/em&gt;(2)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;$ make dup
cc -Wall -static    dup.c   -o dup
$ ./dup -dup &amp;gt; out; cat out; echo
1d
$
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the &lt;em&gt;dup&lt;/em&gt;(2) 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;em&gt;write&lt;/em&gt;(2) updates the file description&amp;rsquo;s file position (&lt;code&gt;f_pos&lt;/code&gt;).  The second &lt;em&gt;write&lt;/em&gt;(2) 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;
&lt;div id=&#39;pikchr-1&#39; class=&#39;pikchr&#39;&gt;
&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:308px&#39;&gt;
&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 308.052 173.52&#34;&gt;
&lt;path d=&#34;M2,63L110,63L110,27L2,27Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;56&#34; y=&#34;45&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;0&lt;/text&gt;
&lt;path d=&#34;M2,99L110,99L110,63L2,63Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;56&#34; y=&#34;81&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;1&lt;/text&gt;
&lt;path d=&#34;M2,135L110,135L110,99L2,99Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;56&#34; y=&#34;117&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;2&lt;/text&gt;
&lt;path d=&#34;M2,171L110,171L110,135L2,135Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;56&#34; y=&#34;153&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;3&lt;/text&gt;
&lt;text x=&#34;2&#34; y=&#34;12&#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;
&lt;path d=&#34;M197,135L305,135L305,81L197,81Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;251&#34; y=&#34;98&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;file&lt;/text&gt;
&lt;text x=&#34;251&#34; y=&#34;118&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;description&lt;/text&gt;
&lt;path d=&#34;M197,171L305,171L305,135L197,135Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;251&#34; y=&#34;153&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;f_pos&lt;/text&gt;
&lt;polygon points=&#34;197,108 185,109 188,100&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M110,81L192,106&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;
&lt;polygon points=&#34;197,121 188,129 185,121&#34; style=&#34;fill:rgb(255,0,0)&#34;/&gt;
&lt;path d=&#34;M110,153L192,123&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(255,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;
&lt;text x=&#34;154&#34; y=&#34;149&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(255,0,0)&#34; transform=&#34;rotate(-19.75051581 154,137)&#34; dominant-baseline=&#34;central&#34;&gt;dup(2)&lt;/text&gt;
&lt;/svg&gt;
&lt;/div&gt;
&lt;/div&gt;
&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;
&lt;pre&gt;&lt;code&gt;$ ./dup -proc &amp;gt; out; cat out; echo
d
$
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the &lt;em&gt;proc&lt;/em&gt;(2) case, we see only one byte written to the output file.
So there are &lt;em&gt;two&lt;/em&gt; &lt;code&gt;struct file&lt;/code&gt;s created &amp;ndash;
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;
&lt;ul&gt;
&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;
&lt;li&gt;The second &lt;em&gt;write&lt;/em&gt;(2) uses a separate file description
and &lt;em&gt;overwrites&lt;/em&gt; the byte that was previously written.&lt;/li&gt;
&lt;/ul&gt;
&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;
&lt;div id=&#39;pikchr-2&#39; class=&#39;pikchr&#39;&gt;
&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:308px&#39;&gt;
&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 308.052 218.52&#34;&gt;
&lt;path d=&#34;M2,63L110,63L110,27L2,27Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;56&#34; y=&#34;45&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;0&lt;/text&gt;
&lt;path d=&#34;M2,99L110,99L110,63L2,63Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;56&#34; y=&#34;81&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;1&lt;/text&gt;
&lt;path d=&#34;M2,135L110,135L110,99L2,99Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;56&#34; y=&#34;117&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;2&lt;/text&gt;
&lt;path d=&#34;M2,171L110,171L110,135L2,135Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;56&#34; y=&#34;153&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;3&lt;/text&gt;
&lt;text x=&#34;2&#34; y=&#34;12&#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;
&lt;path d=&#34;M197,80L305,80L305,26L197,26Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;251&#34; y=&#34;42&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;file&lt;/text&gt;
&lt;text x=&#34;251&#34; y=&#34;63&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;description&lt;/text&gt;
&lt;path d=&#34;M197,116L305,116L305,80L197,80Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;251&#34; y=&#34;98&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;f_pos&lt;/text&gt;
&lt;path d=&#34;M197,180L305,180L305,126L197,126Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;251&#34; y=&#34;143&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;file&lt;/text&gt;
&lt;text x=&#34;251&#34; y=&#34;163&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;description&lt;/text&gt;
&lt;path d=&#34;M197,216L305,216L305,180L197,180Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;251&#34; y=&#34;198&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;f_pos&lt;/text&gt;
&lt;polygon points=&#34;197,53 188,60 185,52&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M110,81L192,54&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;
&lt;polygon points=&#34;197,153 186,157 186,149&#34; style=&#34;fill:rgb(255,0,0)&#34;/&gt;
&lt;path d=&#34;M110,153L192,153&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(255,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;
&lt;text x=&#34;154&#34; y=&#34;165&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(255,0,0)&#34; transform=&#34;rotate(-0 154,153)&#34; dominant-baseline=&#34;central&#34;&gt;open(2)&lt;/text&gt;
&lt;/svg&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;other-file-types&#34;&gt;Other file types&lt;/h3&gt;
&lt;p&gt;So far, this was a bit confusing.  It&amp;rsquo;s definitely inconsistent with
the theory that opening &lt;code&gt;/dev/fd/*&lt;/code&gt; does the same as &lt;em&gt;dup&lt;/em&gt;(2).  But
what happens for other file types than regular files?&lt;/p&gt;
&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;
&lt;p&gt;You can try this out by redirecting stdout to a socket, using the
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;
&lt;pre&gt;&lt;code&gt;$ nc -l 9999 &amp;amp;
[1] 4166
$ ./dup -proc &amp;gt;/dev/tcp/localhost/9999
dup: open /dev/fd/1: No such device or address
[1]+  Done                    nc -l 9999
$ 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The error here is &lt;code&gt;ENXIO: No such device or address&lt;/code&gt;.&lt;/p&gt;
&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;
&lt;pre&gt;&lt;code&gt;lrwx------ 1 gnoack gnoack 64 Feb 17 23:12 1 -&amp;gt; &#39;socket:[16902]&#39;
&lt;/code&gt;&lt;/pre&gt;
&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;
&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;
&lt;pre&gt;&lt;code&gt;$ ./dup -proc | cat ; echo
1d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;hellip;and this works even though the pipe&amp;rsquo;s symlink looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;l-wx------ 1 gnoack gnoack 64 Feb 17 23:10 1 -&amp;gt; &#39;pipe:[15895]&#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;part-2-what-is-really-happening&#34;&gt;Part 2: What is really happening&lt;/h2&gt;
&lt;p&gt;First, let&amp;rsquo;s recall the in-kernel VFS structure:&lt;/p&gt;
&lt;div id=&#39;pikchr-3&#39; class=&#39;pikchr&#39;&gt;
&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:652px&#39;&gt;
&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 652.32 337.32&#34;&gt;
&lt;path d=&#34;M2,164L110,164L110,128L2,128Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;56&#34; y=&#34;146&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;Process&lt;/text&gt;
&lt;polygon points=&#34;182,146 170,150 170,141&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M110,146L176,146&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;146&#34; y=&#34;134&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;fd&lt;/text&gt;
&lt;path d=&#34;M197,164L275,164A15 15 0 0 0 290 149L290,143A15 15 0 0 0 275 128L197,128A15 15 0 0 0 182 143L182,149A15 15 0 0 0 197 164Z&#34;  style=&#34;fill:rgb(255,239,213);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;236&#34; y=&#34;146&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;file object&lt;/text&gt;
&lt;polygon points=&#34;362,146 350,150 350,141&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M290,146L356,146&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;326&#34; y=&#34;134&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;f_path&lt;/text&gt;
&lt;path d=&#34;M362,164L470,164L470,128L362,128Z&#34;  style=&#34;fill:rgb(255,250,205);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;416&#34; y=&#34;146&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;path&lt;/text&gt;
&lt;polygon points=&#34;542,146 530,150 530,141&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M470,146L536,146&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;506&#34; y=&#34;134&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;dentry&lt;/text&gt;
&lt;path d=&#34;M542,164L650,164L650,128L542,128Z&#34;  style=&#34;fill:rgb(176,224,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;596&#34; y=&#34;146&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;dentry&lt;/text&gt;
&lt;polygon points=&#34;596,236 591,224 600,224&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M596,164L596,230&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;596&#34; y=&#34;188&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; transform=&#34;rotate(90 596,200)&#34; dominant-baseline=&#34;central&#34;&gt;d_inode&lt;/text&gt;
&lt;path d=&#34;M557,272L635,272A15 15 0 0 0 650 257L650,251A15 15 0 0 0 635 236L557,236A15 15 0 0 0 542 251L542,257A15 15 0 0 0 557 272Z&#34;  style=&#34;fill:rgb(255,239,213);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;596&#34; y=&#34;254&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;inode object&lt;/text&gt;
&lt;polygon points=&#34;470,254 481,249 481,258&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M542,254L475,254&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;506&#34; y=&#34;242&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;i_sb&lt;/text&gt;
&lt;path d=&#34;M362,281L470,281L470,227L362,227Z&#34;  style=&#34;fill:rgb(255,160,122);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;416&#34; y=&#34;244&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;Superblock&lt;/text&gt;
&lt;text x=&#34;416&#34; y=&#34;264&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;object&lt;/text&gt;
&lt;polygon points=&#34;290,254 301,249 301,258&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M362,254L295,254&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;
&lt;polygon points=&#34;290,308 301,303 301,312&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M596,272L596,308L295,308&#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;
&lt;path d=&#34;M182,237L182,324A54 10 0 0 0 290 324L290,237A54 10 0 0 0 182 237A54 10 0 0 0 290 237&#34;  style=&#34;fill:rgb(219,112,147);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;236&#34; y=&#34;279&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;Disk&lt;/text&gt;
&lt;text x=&#34;236&#34; y=&#34;299&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;file&lt;/text&gt;
&lt;polygon points=&#34;416,56 420,67 411,67&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M416,128L416,61&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;416&#34; y=&#34;80&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; transform=&#34;rotate(-90 416,92)&#34; dominant-baseline=&#34;central&#34;&gt;mnt&lt;/text&gt;
&lt;path d=&#34;M362,56L470,56L470,2L362,2Z&#34;  style=&#34;fill:rgb(255,215,0);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;416&#34; y=&#34;19&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;struct&lt;/text&gt;
&lt;text x=&#34;416&#34; y=&#34;39&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;vfsmount&lt;/text&gt;
&lt;text x=&#34;236&#34; y=&#34;92&#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;
&lt;text x=&#34;236&#34; y=&#34;113&#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;
&lt;/svg&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The following things happen in a sequence:&lt;/p&gt;
&lt;ul&gt;
&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;
&lt;li&gt;System call handler:
&lt;ul&gt;
&lt;li&gt;parses flags&lt;/li&gt;
&lt;li&gt;does the path walk, which eventually invokes &lt;code&gt;proc_pid_get_link()&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;fs/proc/base.c:proc_pid_get_link()&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;invokes &lt;code&gt;proc_fd_link()&lt;/code&gt; through a callback
&lt;ul&gt;
&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;
&lt;/ul&gt;
&lt;/li&gt;
&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;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;eventually calls &lt;code&gt;path_openat()&lt;/code&gt;.
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;namei.c:path_openat()&lt;/code&gt;: &lt;strong&gt;Always&lt;/strong&gt; allocates a new `strucugh an output pointer argument).
&lt;ul&gt;
&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;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;eventually calls &lt;code&gt;path_openat()&lt;/code&gt;.
&lt;ul&gt;
&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;str calls the &amp;quot;open&amp;quot; file operation: &lt;/code&gt;f-&amp;gt;f_op-&amp;gt;open`&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&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;
&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;
&lt;p&gt;&lt;img src=&#34;https://blog.gnoack.org/post/proc-fd-is-not-dup/perf-no_open.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&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;
&lt;h2 id=&#34;summary&#34;&gt;Summary&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Every call to &lt;em&gt;open&lt;/em&gt;(2) results in a new &lt;code&gt;struct file*&lt;/code&gt; being allocated.&lt;/li&gt;
&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;
&lt;li&gt;Not all of the special files support this kind of re-opening.&lt;/li&gt;
&lt;/ul&gt;
&lt;section class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;These &lt;code&gt;/dev/tcp/...&lt;/code&gt; files do not actually exist: bash treats these
paths specially and really just calls the BSD socket API
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;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
    </item>
    
    <item>
      <title>Go-Landlock: Networking support</title>
      <link>https://blog.gnoack.org/post/landlock-v4/</link>
      <pubDate>Wed, 10 Jan 2024 21:23:00 +0100</pubDate>
      
      <guid>https://blog.gnoack.org/post/landlock-v4/</guid>
      <description>&lt;p&gt;In Linux 6.7, Konstantin Meskhidze introduced TCP Networking support
for Landlock. 🚀 I am happy to announce that Go-Landlock is one of the
first libraries using it, and it has a demo tool.&lt;/p&gt;
&lt;h2 id=&#34;demo&#34;&gt;Demo&lt;/h2&gt;
&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;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install the tool to &lt;code&gt;~/go/bin&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go install github.com/landlock-lsm/go-landlock/cmd/landlock-restrict-net@latest
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Invoke the tool using:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;landlock-restrict-net -tcp.bind 8080 /usr/bin/nc -l 127.0.0.1 8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This invokes the command &lt;code&gt;nc -l 127.0.0.1 8080&lt;/code&gt; under a Landlock
policy where 8080 is the only TCP port which can be bound with
&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;.
The command listens on TCP port 8080, so this works.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can see the effect of the sandbox by changing one of the two port numbers:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;landlock-restrict-net -tcp.bind 8081 /usr/bin/nc -l 127.0.0.1 8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case, the &lt;code&gt;nc&lt;/code&gt; command will fail to listen on 8080, because
this port can not be bound.  The sandbox works. 🎉&lt;/p&gt;
&lt;h2 id=&#34;go-api&#34;&gt;Go API&lt;/h2&gt;
&lt;p&gt;Landlock is not only useful to sandbox other programs from the
outside, but it shines when programs sandbox themselves.&lt;/p&gt;
&lt;p&gt;The Go API for Go-Landlock&amp;rsquo;s networking support is in line with the
API that Go-Landlock already provides for file system restrictions:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;err := landlock.V4.BestEffort().RestrictNet(
    landlock.BindTCP(8080),
    landlock.ConnectTCP(25),
    landlock.ConnectTCP(587),
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will enable a Landlock policy on the calling process, where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;only TCP port 8080 can be bound with
&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;
&lt;li&gt;only TCP ports 25 and 587 can be connected to with
&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;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;RestrictNet()&lt;/code&gt; method is a new addition next to the previously
existing &lt;code&gt;RestrictPaths()&lt;/code&gt;.  These methods restrict &lt;em&gt;either&lt;/em&gt;
networking &lt;em&gt;or&lt;/em&gt; file system accesses.&lt;/p&gt;
&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;
method&lt;/a&gt;,
which restricts both networking and file system access at the same
time.&lt;/p&gt;
&lt;p&gt;Non-TCP protocols are currently unaffected by Landlock.  In
particular, UDP can still be freely used independent of any enabled
Landlock policies.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Public tweets are not public, haha!</title>
      <link>https://blog.gnoack.org/post/social-media/</link>
      <pubDate>Wed, 12 Jul 2023 20:38:02 +0200</pubDate>
      
      <guid>https://blog.gnoack.org/post/social-media/</guid>
      <description>&lt;h2 id=&#34;twitter&#34;&gt;Twitter&lt;/h2&gt;
&lt;ul&gt;
&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;
&lt;li&gt;Reading: Most of my timeline is garbage.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;mastodon&#34;&gt;Mastodon&lt;/h2&gt;
&lt;ul&gt;
&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;
&lt;li&gt;Reading: &lt;em&gt;All&lt;/em&gt; of my timeline is garbage.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;m sad for Mastodon. It would have been an opportunity to reverse
the attention-grabbing engagement-through-outrage mechanisms,
which have already annoyed me on other social media platforms.
Somehow this did not work out.&lt;/p&gt;
&lt;h2 id=&#34;the-blogosphere&#34;&gt;The Blogosphere&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Posting: Everything is public, and it does not try to pretend otherwise.&lt;/li&gt;
&lt;li&gt;Reading: Readers control what they are reading through their RSS subscriptions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And this is the winner.&lt;/p&gt;
&lt;h2 id=&#34;summary&#34;&gt;Summary&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;I&amp;rsquo;m ditching Twitter.&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;m not joining Mastodon.&lt;/li&gt;
&lt;li&gt;I keep operating this trusty weblog.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you don&amp;rsquo;t have one yet, &lt;em&gt;get yourself an RSS Reader app&lt;/em&gt;,
and &lt;em&gt;subscribe via RSS&lt;/em&gt;! (see link at the top)&lt;/p&gt;
&lt;section class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34; role=&#34;doc-endnote&#34;&gt;
&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;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34; role=&#34;doc-endnote&#34;&gt;
&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;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
    </item>
    
    <item>
      <title>The Design of Mailprint</title>
      <link>https://blog.gnoack.org/post/mailprint-design/</link>
      <pubDate>Thu, 22 Jun 2023 22:04:56 +0200</pubDate>
      
      <guid>https://blog.gnoack.org/post/mailprint-design/</guid>
      <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;,
for printing out nice-looking emails from &lt;a href=&#34;http://www.mutt.org/&#34;&gt;Mutt&lt;/a&gt;
and other classic Mail user agents.&lt;/p&gt;
&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;
that I have recently spent some time to polish my e-mail setup for kernel development.
While this is not the hip thing to do any more,
some of those mails are difficult to understand,
and I occasionally &lt;em&gt;print them out&lt;/em&gt;.)&lt;/p&gt;
&lt;p&gt;This article describes &lt;em&gt;Mailprint&lt;/em&gt;&amp;rsquo;s internals and design philosophy.
I&amp;rsquo;m fond of this approach, because it fits nicely into the UNIX environment and is reusable.&lt;/p&gt;
&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;
&lt;h2 id=&#34;design-philosophy&#34;&gt;Design philosophy&lt;/h2&gt;
&lt;p&gt;Orthogonal software design, in the UNIX-style,
building one tool for each task, is great.
This applies in particular to side-projects,
because it is a way to achieve a lot more with less work.&lt;/p&gt;
&lt;p&gt;Mailprint is a tool which could have existed in similar form in the 80s already.&lt;/p&gt;
&lt;p&gt;It makes use of a pipeline of other tools to do its job:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GNU troff (&lt;code&gt;groff&lt;/code&gt;) to format pages&lt;/li&gt;
&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;
&lt;/ul&gt;
&lt;h3 id=&#34;interface-to-the-outside&#34;&gt;Interface to the outside&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;To the outside,&lt;/strong&gt;
Mailprint is designed to be used as part of a UNIX pipeline,
reading a plain text email and outputting PDF:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat ~/.Mail/Inbox/cur/foobar123 | mailprint &amp;gt; out.pdf
&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&#39;pikchr-0&#39; class=&#39;pikchr&#39;&gt;
&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:260px&#39;&gt;
&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 260.64 76.32&#34;&gt;
&lt;polygon points=&#34;74,38 62,42 62,33&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M2,38L68,38&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;38&#34; y=&#34;26&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;email&lt;/text&gt;
&lt;path d=&#34;M74,74L182,74L182,2L74,2Z&#34;  style=&#34;fill:rgb(255,255,224);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;128&#34; y=&#34;38&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;mailprint&lt;/text&gt;
&lt;polygon points=&#34;254,38 242,42 242,33&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M182,38L248,38&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;218&#34; y=&#34;26&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;PDF&lt;/text&gt;
&lt;/svg&gt;
&lt;/div&gt;
&lt;/div&gt;
&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;
&lt;h3 id=&#34;internal-design&#34;&gt;Internal design&lt;/h3&gt;
&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;
&lt;div id=&#39;pikchr-1&#39; class=&#39;pikchr&#39;&gt;
&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:980px&#39;&gt;
&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 980.64 236.336&#34;&gt;
&lt;path d=&#34;M93,234L883,234L883,2L93,2Z&#34;  style=&#34;fill:rgb(255,255,224);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;polygon points=&#34;110,181 98,185 98,176&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M2,181L104,181&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;56&#34; y=&#34;169&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;email&lt;/text&gt;
&lt;path d=&#34;M110,217L218,217L218,145L110,145Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;164&#34; y=&#34;181&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;parse email&lt;/text&gt;
&lt;polygon points=&#34;326,181 314,185 314,176&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M218,181L320,181&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;272&#34; y=&#34;169&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;headers,&lt;/text&gt;
&lt;text x=&#34;272&#34; y=&#34;192&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;body&lt;/text&gt;
&lt;path d=&#34;M326,217L434,217L434,145L326,145Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;380&#34; y=&#34;161&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;convert&lt;/text&gt;
&lt;text x=&#34;380&#34; y=&#34;181&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;email&lt;/text&gt;
&lt;text x=&#34;380&#34; y=&#34;201&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;to groff&lt;/text&gt;
&lt;polygon points=&#34;542,181 530,185 530,176&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M434,181L536,181&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;488&#34; y=&#34;169&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;mom&lt;/text&gt;
&lt;text x=&#34;488&#34; y=&#34;192&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;(groff&lt;/text&gt;
&lt;text x=&#34;488&#34; y=&#34;213&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;source)&lt;/text&gt;
&lt;path d=&#34;M542,217L650,217L650,145L542,145Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;596&#34; y=&#34;181&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;preconv&lt;/text&gt;
&lt;polygon points=&#34;758,181 746,185 746,176&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M650,181L752,181&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;704&#34; y=&#34;169&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;mom&lt;/text&gt;
&lt;text x=&#34;704&#34; y=&#34;192&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;(sanitized&lt;/text&gt;
&lt;text x=&#34;704&#34; y=&#34;213&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;Unicode)&lt;/text&gt;
&lt;path d=&#34;M758,217L866,217L866,145L758,145Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;812&#34; y=&#34;171&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;groff&lt;/text&gt;
&lt;text x=&#34;812&#34; y=&#34;191&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;-mom -Tpdf&lt;/text&gt;
&lt;polygon points=&#34;974,181 962,185 962,176&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M866,181L968,181&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;920&#34; y=&#34;169&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;PDF&lt;/text&gt;
&lt;path d=&#34;M164,145L164,73&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;164&#34; y=&#34;97&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; transform=&#34;rotate(-90 164,109)&#34; dominant-baseline=&#34;central&#34;&gt;sender&lt;/text&gt;
&lt;text x=&#34;164&#34; y=&#34;120&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; transform=&#34;rotate(-90 164,109)&#34; dominant-baseline=&#34;central&#34;&gt;address&lt;/text&gt;
&lt;polygon points=&#34;218,73 206,77 206,68&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M164,73L212,73&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M218,109L326,109L326,37L218,37Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;272&#34; y=&#34;63&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;look up&lt;/text&gt;
&lt;text x=&#34;272&#34; y=&#34;83&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;face&lt;/text&gt;
&lt;polygon points=&#34;434,73 422,77 422,68&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M326,73L428,73&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;380&#34; y=&#34;61&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;filename&lt;/text&gt;
&lt;path d=&#34;M434,109L542,109L542,37L434,37Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;488&#34; y=&#34;63&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;ImageMagick&lt;/text&gt;
&lt;text x=&#34;488&#34; y=&#34;83&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;convert&lt;/text&gt;
&lt;polygon points=&#34;650,73 638,77 638,68&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M542,73L644,73&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M650,127L722,127L722,40L700,19L650,19Z&#34;  style=&#34;fill:rgb(255,255,255);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M700,19L700,40L722,40&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;686&#34; y=&#34;63&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;PDF&lt;/text&gt;
&lt;text x=&#34;686&#34; y=&#34;83&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;file&lt;/text&gt;
&lt;polygon points=&#34;812,145 807,133 816,133&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M722,73L812,73L812,139&#34;  style=&#34;fill:none;stroke-width:2.16;stroke-linejoin:round;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;874&#34; y=&#34;12&#34; text-anchor=&#34;end&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;mailprint&lt;/text&gt;
&lt;/svg&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The steps implemented in Go are:&lt;/p&gt;
&lt;ul&gt;
&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;
&lt;li&gt;&lt;strong&gt;Looking up the sender&amp;rsquo;s profile picture:&lt;/strong&gt;
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;
&lt;li&gt;&lt;strong&gt;Converting the email to groff source code&lt;/strong&gt;
&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;,
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;
&lt;/ul&gt;
&lt;p&gt;The remaining steps are accomplished by invoking external UNIX programs:&lt;/p&gt;
&lt;ul&gt;
&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;
&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;
&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;
&lt;/ul&gt;
&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;
&lt;h3 id=&#34;turning-it-inside-out&#34;&gt;Turning it inside-out&lt;/h3&gt;
&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;
&lt;pre&gt;&lt;code&gt;mailprint -face.picon=false -output.format=mom | preconv | groff -mom -Tpdf | lpr
&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&#39;pikchr-2&#39; class=&#39;pikchr&#39;&gt;
&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:980px&#39;&gt;
&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 980.64 127.344&#34;&gt;
&lt;path d=&#34;M93,125L451,125L451,2L93,2Z&#34;  style=&#34;fill:rgb(255,255,224);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;polygon points=&#34;110,72 98,76 98,67&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M2,72L104,72&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;56&#34; y=&#34;60&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;email&lt;/text&gt;
&lt;path d=&#34;M110,108L218,108L218,36L110,36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;164&#34; y=&#34;72&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;parse email&lt;/text&gt;
&lt;polygon points=&#34;326,72 314,76 314,67&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M218,72L320,72&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;272&#34; y=&#34;60&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;headers,&lt;/text&gt;
&lt;text x=&#34;272&#34; y=&#34;83&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;body&lt;/text&gt;
&lt;path d=&#34;M326,108L434,108L434,36L326,36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;380&#34; y=&#34;52&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;convert&lt;/text&gt;
&lt;text x=&#34;380&#34; y=&#34;72&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;email&lt;/text&gt;
&lt;text x=&#34;380&#34; y=&#34;92&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;to groff&lt;/text&gt;
&lt;polygon points=&#34;542,72 530,76 530,67&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M434,72L536,72&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;488&#34; y=&#34;60&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;mom&lt;/text&gt;
&lt;text x=&#34;488&#34; y=&#34;83&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;(groff&lt;/text&gt;
&lt;text x=&#34;488&#34; y=&#34;104&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;source)&lt;/text&gt;
&lt;path d=&#34;M542,108L650,108L650,36L542,36Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;596&#34; y=&#34;72&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;preconv&lt;/text&gt;
&lt;polygon points=&#34;758,72 746,76 746,67&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M650,72L752,72&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;704&#34; y=&#34;60&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;mom&lt;/text&gt;
&lt;text x=&#34;704&#34; y=&#34;83&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;(sanitized&lt;/text&gt;
&lt;text x=&#34;704&#34; y=&#34;104&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;Unicode)&lt;/text&gt;
&lt;path d=&#34;M758,108L866,108L866,36L758,36Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;812&#34; y=&#34;62&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;groff&lt;/text&gt;
&lt;text x=&#34;812&#34; y=&#34;82&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;-mom -Tpdf&lt;/text&gt;
&lt;polygon points=&#34;974,72 962,76 962,67&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M866,72L968,72&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;920&#34; y=&#34;60&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;PDF&lt;/text&gt;
&lt;text x=&#34;442&#34; y=&#34;12&#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;
&lt;/svg&gt;
&lt;/div&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Lei, the Local Email Interface</title>
      <link>https://blog.gnoack.org/post/lei/</link>
      <pubDate>Sun, 11 Jun 2023 20:13:00 +0200</pubDate>
      
      <guid>https://blog.gnoack.org/post/lei/</guid>
      <description>&lt;h2 id=&#34;intro&#34;&gt;Intro&lt;/h2&gt;
&lt;p&gt;The Linux kernel mailing lists are known to be high volume,
and it&amp;rsquo;s easy to fill your email storage space with them.
But if you are anyway reading your mail locally,
there is a better option where you simply synchronize your
local mail storage with the public mailing list archives.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;lei&lt;/code&gt; program lets you import Linux mailing list archives into local maildirs:&lt;/p&gt;
&lt;div id=&#39;pikchr-0&#39; class=&#39;pikchr&#39;&gt;
&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:481px&#39;&gt;
&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 481.219 205.013&#34;&gt;
&lt;path d=&#34;M11,202L119,202L119,130L11,130Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;65&#34; y=&#34;156&#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;
&lt;text x=&#34;65&#34; y=&#34;176&#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;
&lt;polygon points=&#34;119,166 130,162 130,171&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M124,166L191,166&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;155&#34; y=&#34;155&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;2. query&lt;/text&gt;
&lt;path d=&#34;M191,202L299,202L299,130L191,130Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;245&#34; y=&#34;166&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;lei&lt;/text&gt;
&lt;polygon points=&#34;371,166 359,171 359,162&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M299,166L365,166&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;335&#34; y=&#34;155&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;3. store&lt;/text&gt;
&lt;path d=&#34;M371,141L371,192A54 10 0 0 0 479 192L479,141A54 10 0 0 0 371 141A54 10 0 0 0 479 141&#34;  style=&#34;fill:rgb(255,255,224);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;425&#34; y=&#34;164&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;local&lt;/text&gt;
&lt;text x=&#34;425&#34; y=&#34;185&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;maildir&lt;/text&gt;
&lt;polygon points=&#34;245,130 240,119 249,119&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M245,125L245,74&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;245&#34; y=&#34;102&#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;
&lt;path d=&#34;M191,74L299,74L299,2L191,2Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:7.2,7.2;&#34; /&gt;
&lt;text x=&#34;245&#34; y=&#34;38&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;user&lt;/text&gt;
&lt;/svg&gt;
&lt;/div&gt;
&lt;/div&gt;
&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;
&lt;h2 id=&#34;set-up&#34;&gt;Set up&lt;/h2&gt;
&lt;p&gt;First, create a directory for your maildirs:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir -p .Mail/lei
&lt;/code&gt;&lt;/pre&gt;
&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;
&lt;pre&gt;&lt;code&gt;alias lei=/usr/bin/vendor_perl/lei
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;subscriptionsearch-management&#34;&gt;Subscription/Search management&lt;/h2&gt;
&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;
&lt;pre&gt;&lt;code&gt;# Linux Security Module list
lei q --only=https://lore.kernel.org/linux-security-module \
      --output=&amp;quot;${HOME}/.Mail/lei/lsm&amp;quot;                     \
      &#39;rt:12.months.ago..&#39;

# Linux Man Pages list
lei q --only=https://lore.kernel.org/linux-man \
      --output=&amp;quot;${HOME}/.Mail/lei/man&amp;quot;         \
      &#39;rt:12.months.ago..&#39;

# Mails where I am in To: or Cc:, and the surrounding threads
lei q --only=https://lore.kernel.org/all \
      --output=&amp;quot;${HOME}/.Mail/lei/tome&amp;quot;  \
      --threads                          \
      &#39;a:myemail@example.com rt:36.months.ago..&#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;lei q&lt;/code&gt; command is not issuing a single-shot query,
but it is storing the query locally as a subscription.&lt;/p&gt;
&lt;p&gt;These subscriptions are called &amp;ldquo;searches&amp;rdquo; in lei lingo,
and their results are stored in the given maildir directories.&lt;/p&gt;
&lt;p&gt;To see all the searches you have, use:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lei ls-search
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To remove an existing search, use&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lei forget-search &amp;quot;${HOME}/.Mail/lei/lsm&amp;quot;  # example
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;regularly-update-subscriptionssearches&#34;&gt;Regularly: Update subscriptions/searches&lt;/h2&gt;
&lt;p&gt;To update all lei subscriptions and populate new content into the maildirs:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lei up --all
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you are all set, and you can read the mailing lists with the MUA of your choice:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mutt -f ~/.Mail/lei/lsm
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;references&#34;&gt;References&lt;/h2&gt;
&lt;ul&gt;
&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;
&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;
&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;
&lt;/ul&gt;
&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;
</description>
    </item>
    
    <item>
      <title>The empty Makefile is valid</title>
      <link>https://blog.gnoack.org/post/empty-makefiles/</link>
      <pubDate>Wed, 10 May 2023 19:00:00 +0200</pubDate>
      
      <guid>https://blog.gnoack.org/post/empty-makefiles/</guid>
      <description>&lt;p&gt;This is less of a &amp;ldquo;Today I learned&amp;rdquo; article, but more like a Unix
trick that took me too long to realize.&lt;/p&gt;
&lt;p&gt;Create a new directory with a hello world C program:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ls
$ cat &amp;gt; hello.c
#include &amp;lt;stdio.h&amp;gt;

int main() {
  puts(&amp;quot;Hello, world!&amp;quot;);
  return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;💡 The empty or non-existent Makefile is a valid makefile for this C
program:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ make hello                # build &amp;quot;hello&amp;quot;
cc     hello.c   -o hello
$ ./hello
Hello, world!
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>Landlock: Best Effort mode</title>
      <link>https://blog.gnoack.org/post/landlock-best-effort/</link>
      <pubDate>Sun, 05 Mar 2023 10:34:09 +0100</pubDate>
      
      <guid>https://blog.gnoack.org/post/landlock-best-effort/</guid>
      <description>&lt;p&gt;One of Landlock&amp;rsquo;s strengths is that you can deploy the same program on
multiple kernel versions, and make it use the best available
sandboxing on each.&lt;/p&gt;
&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
Go-Landlock
library&lt;/a&gt;
and &lt;a href=&#34;https://landlock.io/rust-landlock/landlock/#compatibility&#34;&gt;in the Rust Landlock
library&lt;/a&gt;.
But what if you need to implement it yourself?&lt;/p&gt;
&lt;blockquote class=&#34;info&#34;&gt;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;/blockquote&gt;

&lt;h2 id=&#34;abi-versions-and-matching-access-rights&#34;&gt;ABI versions and matching access rights&lt;/h2&gt;
&lt;!-- TODO: Link the man page here when it&#39;s part of the man page --&gt;
&lt;p&gt;Landlock exposes its feature set in the form of a numeric Landlock ABI
version.&lt;/p&gt;
&lt;p&gt;In order to implement the fallback correctly, you need to know which
file system access rights are supported in which ABI version.&lt;/p&gt;
&lt;p&gt;The (simplified) compatibility chart as of Linux 6.2 is:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ABI&lt;/th&gt;
&lt;th&gt;Linux&lt;/th&gt;
&lt;th&gt;File system access rights&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;5.13&lt;/td&gt;
&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;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;5.19&lt;/td&gt;
&lt;td&gt;+&lt;code&gt;LANDLOCK_ACCESS_FS_REFER&lt;/code&gt; (reparenting files)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;6.2&lt;/td&gt;
&lt;td&gt;+&lt;code&gt;LANDLOCK_ACCESS_FS_TRUNCATE&lt;/code&gt; (truncating files)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Further below, we will define this support matrix in C.&lt;/p&gt;
&lt;h2 id=&#34;the-problem-refer-is-different&#34;&gt;The problem: Refer is different&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The backwards compatibility works differently for &amp;ldquo;refer&amp;rdquo; than for
other access rights&lt;/strong&gt;.&lt;/p&gt;
&lt;div class=&#34;sidenote&#34;&gt;Skip this section if you are only interested in the C code.&lt;/div&gt;
&lt;p&gt;Each Landlock ABI version is characterized by three disjoint sets of
file system operations: The &lt;em&gt;Always Forbidden&lt;/em&gt; operations, the
&lt;em&gt;Configurable&lt;/em&gt; operations and the &lt;em&gt;Always Permitted&lt;/em&gt; operations.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;Configurable&lt;/em&gt; operations are the ones which already have names in
the &lt;code&gt;landlock.h&lt;/code&gt; header.  With increasing ABI versions, all relevant
operations should become &amp;ldquo;Configurable&amp;rdquo;, in particular the &amp;ldquo;Always
permitted&amp;rdquo; operations.&lt;/p&gt;
&lt;p&gt;In ABI v1, an set of useful file system operations is configurable in
Landlock, but there is also a longer list of known operations which is
always permitted (Landlock can not restrict them). Finally, some more
complicated interactions are always forbidden because they would
interfere with Landlock&amp;rsquo;s guarantees:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.gnoack.org/images/ll-permissions.svg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;When introducing ABI v2, the &amp;ldquo;refer&amp;rdquo; operation, which was previously
forbidden, became configurable:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.gnoack.org/images/ll-permissions-v2.svg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;With ABI v2, it is now possible to reparent (link(2) or rename(2))
files between different directories, as long as the involved files and
directories meet certain constraints about their access rights.&lt;/p&gt;
&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;
&lt;blockquote class=&#34;rule&#34;&gt;&lt;b&gt;Rule:&lt;/b&gt; If a program needs to do a &amp;ldquo;refer&amp;rdquo; (reparent files between directories),
using ABI v1 is not an option.&lt;/blockquote&gt;

&lt;!-- todo: mention man page --&gt;
&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
documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;implementation-of-best-effort-fallback-in-c&#34;&gt;Implementation of best-effort fallback in C&lt;/h2&gt;
&lt;p&gt;To implement the fallback logic, we will (a) define the compatibility
table, and then, (b) depending on whether your program needs to do
file reparenting, implement a slightly different fallback logic based
on that compatibility table.&lt;/p&gt;
&lt;div class=&#34;sidenote&#34;&gt;This question decides which approach to use.&lt;/div&gt;
&lt;p&gt;The question to ask is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Does your program need to do any file reparenting (&amp;ldquo;refer&amp;rdquo;)?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;File reparenting means: Creating hard links or moving files or
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
documentation&lt;/a&gt;).&lt;/p&gt;
&lt;h3 id=&#34;common-part-abi-version-compatibility-table&#34;&gt;Common part: ABI version compatibility table&lt;/h3&gt;
&lt;p&gt;We define a small C array to hold the file system access rights which
are supported by the different Landlock ABI versions.  We store one
&lt;code&gt;__u64&lt;/code&gt; bitmask for each ABI version.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;__u64 landlock_fs_access_rights[] = {
  (1ULL &amp;lt;&amp;lt; 13) - 1,  /* ABI v1                 */
  (1ULL &amp;lt;&amp;lt; 14) - 1,  /* ABI v2: add &amp;quot;refer&amp;quot;    */
  (1ULL &amp;lt;&amp;lt; 15) - 1,  /* ABI v3: add &amp;quot;truncate&amp;quot; */
};
&lt;/code&gt;&lt;/pre&gt;
&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;
&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;
&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;
&lt;p&gt;If the sandboxed program does &lt;em&gt;not&lt;/em&gt; need to reparent files, the
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;
&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
from it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int abi = landlock_create_ruleset(NULL, 0,
                                  LANDLOCK_CREATE_RULESET_VERSION);
if (abi &amp;lt;= 0) {
  /*
   * This kernel does not let us use Landlock.
   * Best effort: Give up, and do not restrict the process.
   */
  return 0;
}
if (abi &amp;gt; ARRAY_SIZE(landlock_fs_access_rights)) {
  /* Kernel from the future: Treat as highest known ABI version. */
  abi = ARRAY_SIZE(landlock_fs_access_rights);
}
ruleset_attr.handled_access_fs &amp;amp;= landlock_fs_access_rights[abi-1];
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;sidenote&#34;&gt;Don&#39;t forget this!&lt;/div&gt;
&lt;p&gt;Additionally, before you add a &amp;ldquo;path beneath&amp;rdquo; Landlock rule to the
ruleset, make sure that the requested access rights fit into the
previously restricted &lt;code&gt;handled_access_fs&lt;/code&gt; rights:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;path_beneath.allowed_access &amp;amp;= ruleset_attr.handled_access_fs;
&lt;/code&gt;&lt;/pre&gt;
&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;
&lt;p&gt;If the sandboxed program &lt;em&gt;does&lt;/em&gt; need to reparent files, the
best-effort logic works the same as above, &lt;em&gt;but it has a special case
for ABI version 1&lt;/em&gt;.  In this ABI version, file reparenting does not
work under Landlock at all, and so we have to give up on it.&lt;/p&gt;
&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
from it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int abi = landlock_create_ruleset(NULL, 0,
                                  LANDLOCK_CREATE_RULESET_VERSION);
switch (abi) {
  case -1:
  case 0:  /* should not happen */
    /*
     * This kernel does not let us use Landlock.
     * Best effort: Give up, and do not restrict the process.
     */
    return 0;
  case 1:
    /*
     * This kernel only supports Landlock ABI v1.
     * We need the &amp;quot;refer&amp;quot; right, but it&#39;s not supported in ABI v1.
     * Best effort: Give up, and do not restrict the process.
     */
    return 0;
  default:
    if (abi &amp;gt; ARRAY_SIZE(landlock_fs_access_rights)) {
      /* 
       * A kernel with Landlock suppport from the future!
       * Treat it as the highest known ABI version.
       */
      abi = ARRAY_SIZE(landlock_fs_access_rights);
    }
    ruleset_attr.handled_access_fs &amp;amp;= landlock_fs_access_rights[abi-1];
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally, before you add a &amp;ldquo;path beneath&amp;rdquo; Landlock rule to the
ruleset, make sure that the requested access rights fit into the
previously restricted &lt;code&gt;handled_access_fs&lt;/code&gt; rights:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;path_beneath.allowed_access &amp;amp;= ruleset_attr.handled_access_fs;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;case-3-sometimes-this-sometimes-that&#34;&gt;Case 3: Sometimes this, sometimes that&lt;/h3&gt;
&lt;p&gt;This is the complicated case which we also implemented in the Go and
Rust Landlock libraries.  These libraries figure out at runtime which
of the two cases we are in, and then use the adequate approach as
above.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In the long run, when Landlock has stabilized more, and as older
kernels become less relevant, this complication will hopefully go
away.  Until then, I&amp;rsquo;m hopeful that most users can simply use the
simple approach in Case 1 above, because their programs do not need
the &amp;ldquo;refer&amp;rdquo; right.&lt;/p&gt;
&lt;h2 id=&#34;references&#34;&gt;References&lt;/h2&gt;
&lt;ul&gt;
&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
Model&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://landlock.io/&#34;&gt;https://landlock.io/&lt;/a&gt; - Official Landlock page&lt;/li&gt;
&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;
&lt;/ul&gt;
&lt;p&gt;Thank you Mickaël, for pointing out some issues in this article!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Landlock truncation support in Linux 6.2</title>
      <link>https://blog.gnoack.org/post/landlock-truncate/</link>
      <pubDate>Mon, 20 Feb 2023 21:20:00 +0100</pubDate>
      
      <guid>https://blog.gnoack.org/post/landlock-truncate/</guid>
      <description>&lt;p&gt;Linus Torvalds released Linux 6.2 yesterday, and this kernel release
supports restricting the &lt;code&gt;truncate(2)&lt;/code&gt; and &lt;code&gt;ftruncate(2)&lt;/code&gt; operations
with Landlock. (The &lt;a href=&#34;https://lore.kernel.org/all/20221018182216.301684-1-gnoack3000@gmail.com/&#34;&gt;kernel patch
set&lt;/a&gt;
has more information and discussion.)&lt;/p&gt;
&lt;p&gt;You can try this out today with the
&lt;a href=&#34;https://github.com/landlock-lsm/go-landlock&#34;&gt;go-landlock&lt;/a&gt; library,
which already supports this feature. To forbid file truncation when
using &lt;code&gt;go-landlock&lt;/code&gt;, update your &lt;code&gt;RestrictPaths()&lt;/code&gt; invocation to use
Landlock version 3 as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;err := landlock.V3.BestEffort().RestrictPaths(
    landlock.RODirs(&amp;quot;/usr&amp;quot;, &amp;quot;/bin&amp;quot;),
    landlock.RWDirs(&amp;quot;/tmp&amp;quot;),
)
&lt;/code&gt;&lt;/pre&gt;
&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
using &lt;code&gt;landlock.V3&lt;/code&gt; this way, file truncation is forbidden by default.&lt;/p&gt;
&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
used on a file or directory. (It comes hand in hand with the right to
open files for writing.)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Why use Go-Landlock for sandboxing?</title>
      <link>https://blog.gnoack.org/post/go-landlock-talk/</link>
      <pubDate>Mon, 14 Nov 2022 20:00:00 +0100</pubDate>
      
      <guid>https://blog.gnoack.org/post/go-landlock-talk/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is the article version of a talk I presented a the Zurich
Gophers Meetup on 2022-10-25, with some less relevant parts
shortened.&lt;/p&gt;
&lt;p&gt;The slides are also available at
&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;
&lt;/blockquote&gt;
&lt;h2 id=&#34;motivation&#34;&gt;Motivation&lt;/h2&gt;
&lt;p&gt;I started to get interested in computer security about 20 years ago.
In the late 90&amp;rsquo;s and early 2000&amp;rsquo;s, buffer overflow exploits were all
the rage and started to be more widely understood and researched.&lt;/p&gt;
&lt;p&gt;This image depicts a high level overview over a common pattern of a
technical attack (&amp;ldquo;exploit&amp;rdquo;) on a computer program:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.gnoack.org/talks/go-landlock/Go-Landlock-1.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;div class=&#34;sidenote&#34;&gt;The attack channel can take many forms, such as
over the network, by invoking a privileged executable file, or by
distributing crafted input files.&lt;/div&gt;
The attacker talks to the attacked process through the same channels
like any other user would do. But unlike another user&#39;s input, the
attacker&#39;s input is maliciously crafted to trick the attacked process
into misinterpreting or wrongly validating it, and thereby doing
things on behalf of the attacker that it was not originally designed
to do.
&lt;p&gt;This can range from exposing process-local memory (e.g.
&lt;a href=&#34;https://en.wikipedia.org/wiki/Heartbleed&#34;&gt;Heartbleed&lt;/a&gt;), to exposing
the contents of files that were not intended to be exposed (e.g.
&lt;a href=&#34;https://en.wikipedia.org/wiki/Directory_traversal_attack&#34;&gt;directory traversal
attacks&lt;/a&gt;),
to even giving the attacker full control over the attacked process
(e.g. a &lt;a href=&#34;https://en.wikipedia.org/wiki/Buffer_overflow#Exploitation&#34;&gt;classic buffer overflow
exploit&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Now all of this would be less critical, if the attacked process only
had access to the resources that it needs for execution, but as it
turns out, in the normal UNIX model, access rights are usually
determined by the user that a program runs as, and that often means
that these programs have access to significantly more things than they
need. (&lt;a href=&#34;https://en.wikipedia.org/wiki/Ambient_authority&#34;&gt;Ambient
Authority&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;For instance, programs that you run on your desktop are going to have
access to your bank documents, your (hopefully encrypted) SSH and PGP
keys, your cookies, your git repositories, etc.&lt;/p&gt;
&lt;p&gt;&amp;ndash; so: &lt;strong&gt;Let&amp;rsquo;s limit this ambient access!&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;philosophy&#34;&gt;Philosophy&lt;/h2&gt;
&lt;p&gt;I can&amp;rsquo;t speak for Mickaël Salaün&amp;rsquo;s vision for sandboxing, but this is
mine, and it aligns very well with Landlock&amp;rsquo;s approach.&lt;/p&gt;
&lt;p&gt;First of all, I hold the belief that:&lt;/p&gt;
&lt;blockquote class=&#34;info&#34;&gt;&lt;strong&gt;Software authors are generally well-meaning&lt;/strong&gt;. They want
their software to work, and to be secure. If provided with the right
tools for securing applications, they will use them.&lt;/blockquote&gt;

&lt;p&gt;However, if we take a look at the adoption of unprivileged sandboxing
on Linux (namely, seccomp-bpf), it shows that there are only a handful
of programs making use of it &amp;ndash; but what is the reason for that?&lt;/p&gt;
&lt;p&gt;Which leads me to this hypothesis:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.gnoack.org/talks/go-landlock/Go-Landlock-4.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;blockquote class=&#34;info&#34;&gt;&lt;strong&gt;It is too difficult&lt;/strong&gt; for software authors to confine
their software to have &lt;em&gt;just&lt;/em&gt; the access that the software needs, even
though these software authors are in the best position to reason about
the required scope of access.&lt;/blockquote&gt;

&lt;h3 id=&#34;the-landlock-approach&#34;&gt;The Landlock approach&lt;/h3&gt;
&lt;p&gt;There are two main points that I&amp;rsquo;d like to push for in Go-Landlock,
which I think make it more usable for sandboxing than other
approaches:&lt;/p&gt;
&lt;h4 id=&#34;1-make-it-really-easy-to-use&#34;&gt;1. Make it really easy to use&lt;/h4&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.gnoack.org/talks/go-landlock/Go-Landlock-5.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;The existing confinement approaches on Linux tend to be too difficult
to set up or maintain, which means that they don&amp;rsquo;t get used as much as
they should.&lt;/p&gt;
&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;
&lt;p&gt;&lt;img src=&#34;https://blog.gnoack.org/talks/go-landlock/Go-Landlock-6.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;This is the other main idea &amp;ndash; it should be up to each process to
enable its own sandbox.&lt;/p&gt;
&lt;p&gt;The rough approach is:&lt;/p&gt;
&lt;ul&gt;
&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;
&lt;li&gt;The program &lt;strong&gt;restricts its own access&lt;/strong&gt; (using Landlock)&lt;/li&gt;
&lt;li&gt;The program &lt;strong&gt;starts processing untrusted input&lt;/strong&gt; from potentially malicious sources&lt;/li&gt;
&lt;/ul&gt;
&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;,
because they can also drop the permissions that were required for
their initialization phase.&lt;/p&gt;
&lt;p&gt;UNIX enforces permissions when &lt;em&gt;opening&lt;/em&gt; files, so an already opened
file can continue to get used by a process, even when it does not have
the permissions to open the file again.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;other-operating-systems&#34;&gt;Other operating systems&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.gnoack.org/talks/go-landlock/Go-Landlock-7.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;These ideas are not new - OpenBSD has demonstrated the feasability of
this approach with &lt;code&gt;pledge()&lt;/code&gt; and &lt;code&gt;unveil()&lt;/code&gt;, which is now used in
&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
programs&lt;/a&gt;. Various
slide decks on the topic can be found at
&lt;a href=&#34;https://www.openbsd.org/events.html&#34;&gt;https://www.openbsd.org/events.html&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://wiki.freebsd.org/Capsicum&#34;&gt;Capsicum on FreeBSD&lt;/a&gt; is another
unprivileged sandboxing mechanism, which is used in Chromium and other
programs (see its homepage). Capsicum is a flexible capability system,
but it also has a larger API surface.&lt;/p&gt;
&lt;h3 id=&#34;other-linux-sandboxing-technologies&#34;&gt;Other Linux sandboxing technologies&lt;/h3&gt;
&lt;p&gt;A deeper discussion of seccomp-bpf and the various Linux Security
Modules would be beyond the scope of this article.&lt;/p&gt;
&lt;p&gt;For a discussion of the other unprivileged sandboxing mechanism, see
&lt;a href=&#34;https://blog.gnoack.org/post/pledge-on-linux/&#34;&gt;my previous article about
it&lt;/a&gt; on this blog.&lt;/p&gt;
&lt;p&gt;The other Linux sandboxing mechanisms are either only available to
privileged users, or they are still very difficult to set up.&lt;/p&gt;
&lt;h2 id=&#34;how-to-use-go-landlock&#34;&gt;How to use Go-Landlock&lt;/h2&gt;
&lt;p&gt;This diagram shows the overall approach for program initialization
when using Landlock (it&amp;rsquo;s a more detailed view of the program
initialization overview diagram from above):&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.gnoack.org/talks/go-landlock/Go-Landlock-10.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;The important parts here are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Primarily, &lt;strong&gt;Landlock is a Linux kernel feature&lt;/strong&gt; &amp;ndash; the access
policies enforced through Landlock apply to both the enforcing
program, as well as all newly forked subprocesses, independent of
the libraries being used to do these accesses.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Go-Landlock library is only required to configure and enforce
the Landlock policy&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The steps required to enforce Landlock are:&lt;/p&gt;
&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;
&lt;p&gt;&lt;img src=&#34;https://blog.gnoack.org/talks/go-landlock/Go-Landlock-11.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For development&lt;/strong&gt;, it&amp;rsquo;s recommended to double check that Landlock is
already working, so that you can try out your policies. Landlock is
already enabled on many major distributions today.&lt;/p&gt;
&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;
&lt;p&gt;On systems that do not have it yet:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make sure Landlock is compiled into the kernel.&lt;/li&gt;
&lt;li&gt;Set the &lt;code&gt;lsm=landlock&lt;/code&gt; boot parameter (or configure it in
&lt;code&gt;CONFIG_LSM&lt;/code&gt; at build time).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;For deployment&lt;/strong&gt;, you can pick whether your program should insist on
running on a Landlock-enabled kernel, or whether it should fall back
to using weaker (or no) Landlock policies on older systems:&lt;/p&gt;
&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;
&lt;p&gt;This is the only function invocation your program needs in order to
confine itself in a Landlock policy:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.gnoack.org/talks/go-landlock/Go-Landlock-12.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;ul&gt;
&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
version means that more operations can be restricted.
(Alternatively, you can also spell out the exact operations that you
want to restrict.)&lt;/li&gt;
&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
gracefully degrade to weaker Landlock policies on systems that do
not have the requested Landlock features.&lt;/li&gt;
&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;
&lt;li&gt;&lt;strong&gt;The arguments to &lt;code&gt;.RestrictPaths()&lt;/code&gt;&lt;/strong&gt; are file system hierarchies
that the process intends to still access going forward. Access to
all paths other than the listed ones will be forbidden, as much as
the Landlock ABI permits. (Landlock does not currently restrict
&lt;em&gt;all&lt;/em&gt; possible file system operations, but that&amp;rsquo;s eventually the
goal. A more detailed look is in the appendix below.)&lt;/li&gt;
&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
identify &amp;ldquo;general read-only&amp;rdquo; operations and &amp;ldquo;general read-write
operations&amp;rdquo;. This can also be configured in more detail if needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;hellip;and that&amp;rsquo;s it. After this invocation, your program will be unable
to work with files other than the ones specified or the ones that have
already been opened before.&lt;/p&gt;
&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;
&lt;h2 id=&#34;examples&#34;&gt;Examples&lt;/h2&gt;
&lt;p&gt;This section will list a few practical examples.&lt;/p&gt;
&lt;h3 id=&#34;image-converter&#34;&gt;Image converter&lt;/h3&gt;
&lt;p&gt;This is a basic image conversion tool in the spirit of ImageMagick&amp;rsquo;s
&amp;ldquo;convert&amp;rdquo;. Multimedia processing libraries are often optimized for
performance and can be particularly prone to programming bugs, and we
want to protect against attackers providing malicious image files as
input.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.gnoack.org/talks/go-landlock/Go-Landlock-13.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;In this example, the Landlock invocation happens right at the start
and is &lt;code&gt;landlock.V2.BestEffort().RestrictPaths()&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We simply restrict to &lt;strong&gt;no file system access at all&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;But we fall back to enforcing weaker Landlock policies or none, if
it&amp;rsquo;s not supported by the system where the program is running.&lt;/li&gt;
&lt;/ul&gt;
&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;
&lt;h3 id=&#34;web-server&#34;&gt;Web Server&lt;/h3&gt;
&lt;p&gt;This simple wiki software only needs access to the directory where the
wiki pages are stored.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.gnoack.org/talks/go-landlock/Go-Landlock-14.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;The Go-Landlock invocation is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;err = landlock.V2.BestEffort().RestrictPaths(
    landlock.RWDirs(*storeDir),
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This gives the process the right to serve and edit the wiki pages, but
removes the rights for all other file paths (within the limits of what
is possible on the current system).&lt;/p&gt;
&lt;p&gt;(Small side note: The &lt;code&gt;net.Listen()&lt;/code&gt; call happens before Landlock
enablement &amp;ndash; I am using this with a named UNIX domain socket.)&lt;/p&gt;
&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;
&lt;h3 id=&#34;the-go-landlock-example-tool&#34;&gt;The Go-Landlock example tool&lt;/h3&gt;
&lt;p&gt;The Go-landlock library comes with a simple example tool, which lets
you play with Landlock from bash, similar to the one in the
&lt;code&gt;samples/landlock&lt;/code&gt; subdirectory in the kernel source, but written
using the Go library:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.gnoack.org/talks/go-landlock/Go-Landlock-15.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;The command to install the &lt;code&gt;landlock-restrict&lt;/code&gt; tool is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;go install github.com/landlock-lsm/go-landlock/cmd/landlock-restrict@latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above shell transcript starts &lt;code&gt;bash&lt;/code&gt; under a Landlock policy where
it only has access to these files:&lt;/p&gt;
&lt;ul&gt;
&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
and the &lt;code&gt;bash&lt;/code&gt; executable itself.&lt;/li&gt;
&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
files.&lt;/li&gt;
&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
&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;
&lt;li&gt;&lt;strong&gt;Write access to $HOME&lt;/strong&gt;: We rewire the &lt;code&gt;$HOME&lt;/code&gt; environment
variable to a temporary directory for our subprocess and set
&lt;code&gt;$TMPDIR&lt;/code&gt; to a directory within it, so we can just grant write
access to &lt;code&gt;$HOME&lt;/code&gt;. (This trick makes it possible to use a coarser
policy, but it lets the sandboxes process execute in a slightly less
usual environment.)&lt;/li&gt;
&lt;/ul&gt;
&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;
&lt;h2 id=&#34;current-landlock-limitations&#34;&gt;Current Landlock limitations&lt;/h2&gt;
&lt;p&gt;Some things that Landlocked processes can never do are:&lt;/p&gt;
&lt;ul&gt;
&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;
&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;
&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;
&lt;/ul&gt;
&lt;p&gt;Also,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Landlock is &lt;em&gt;in development&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Some file operations are not restrictable yet&lt;/li&gt;
&lt;li&gt;But it&amp;rsquo;s already limiting the most common ones and it&amp;rsquo;s already usable&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;what-file-system-operations-are-restrictable&#34;&gt;What file system operations are restrictable?&lt;/h3&gt;
&lt;p&gt;Landlock gains features and makes it possible to restrict more file
system operations. To make this observable, Landlock&amp;rsquo;s ABI is
versioned. As of November 2022, the current ABI is V2.&lt;/p&gt;
&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
Landlock
documentation&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote class=&#34;warning&#34;&gt;&lt;strong&gt;Warning&lt;/strong&gt;: Not all file system operations can be
restricted yet. Currently, notable exceptions are file truncation (as
a form of file modification), and various ways to observe presence and
metadata of files (but not reading their contents).&lt;/blockquote&gt;

&lt;p&gt;In future Landlock ABI versions, new operations will start to be
configurable. Currently ongoing patch sets (as of November 2022) are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;File truncation (currently scheduled for inclusion in kernel 6.2)&lt;/li&gt;
&lt;li&gt;Chmod and Chown (patch set in review)&lt;/li&gt;
&lt;li&gt;Networking support (patch set in review)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;summary&#34;&gt;Summary&lt;/h2&gt;
&lt;p&gt;In short, please try it out! The invocation is as simple as:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;err := landlock.V2.BestEffort().RestrictPaths(
    landlock.RODirs(&amp;quot;/usr&amp;quot;, &amp;quot;/bin&amp;quot;),
    landlock.RWDirs(&amp;quot;/tmp&amp;quot;),
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I would love to hear your feedback!&lt;/p&gt;
&lt;h2 id=&#34;further-links&#34;&gt;Further Links&lt;/h2&gt;
&lt;p&gt;For further reference, here are some additional links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go-Landlock:
&lt;ul&gt;
&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;
&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;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Landlock kernel project:
&lt;ul&gt;
&lt;li&gt;Page: &lt;a href=&#34;https://landlock.io/&#34;&gt;https://landlock.io/&lt;/a&gt;&lt;/li&gt;
&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;
&lt;/ul&gt;
&lt;/li&gt;
&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
&lt;a href=&#34;mailto:landlock+subscribe@lists.linux.dev&#34;&gt;landlock+subscribe@lists.linux.dev&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Some more documentation:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.google.com/document/d/1SkFpl_Xxyl4E6G2uYIlzL0gY2PFo-Nl8ikblLvnpvlU/edit&#34;&gt;Landlock File System Access
Model&lt;/a&gt;
(discussing the kernel API and configurable file system operations
in a more mathematical way).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>The feasibility of pledge() on Linux</title>
      <link>https://blog.gnoack.org/post/pledge-on-linux/</link>
      <pubDate>Sat, 16 Jul 2022 10:36:20 +0200</pubDate>
      
      <guid>https://blog.gnoack.org/post/pledge-on-linux/</guid>
      <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;
about her port of &lt;a href=&#34;https://man.openbsd.org/pledge.2&#34;&gt;OpenBSD&amp;rsquo;s
&lt;code&gt;pledge()&lt;/code&gt;&lt;/a&gt; to her own libc, the
&lt;a href=&#34;https://justine.lol/cosmopolitan/&#34;&gt;Cosmopolitan libc&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;She is also calling out that previous attempts at this were flawed:&lt;/p&gt;
&lt;blockquote&gt;
&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;
&lt;/blockquote&gt;
&lt;p&gt;My own &lt;a href=&#34;https://github.com/gnoack/seccomp-scopes&#34;&gt;seccomp-scopes&lt;/a&gt;
project which I worked on from 2016 onwards is one of these attempts,
so I feel I should explain the reasons &lt;em&gt;why&lt;/em&gt; I stopped pursuing this
approach of unprivileged sandboxing, and what I think needs to get
done to do it right.&lt;/p&gt;
&lt;p&gt;At the high level, the main problem is that seccomp-bpf does its
filtering at the level of system calls and &lt;strong&gt;software libraries
generally do not give guarantees about which system calls they are
using under the hood&lt;/strong&gt;. This does not even hold for &lt;code&gt;libc&lt;/code&gt;
implementations.&lt;/p&gt;
&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;
&lt;p&gt;Here are some ways in which glibc makes it hard to predict which
system calls it will do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;glibc replaces existing uses of system calls with newer variants. A
call to the &lt;code&gt;open()&lt;/code&gt; libc function used the &lt;code&gt;openat(2)&lt;/code&gt; syscall
under the hood, and that is just one of many examples. This changes
between glibc versions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;glibc initializes parts of the library on demand when they are first
used, and that may involve system calls that should better be
forbidden. So this initialization needs to ideally be done before
enforcing seccomp.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;glibc makes use of shared libraries for commonly used functionality
(&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;).
Administrators can flexibly install additional ways of doing name
lookups, but any attempt at reasoning about this will need to
involve these shared libraries as well.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&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;
&lt;ul&gt;
&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;
&lt;li&gt;It loads these shared libraries (system calls: various file accesses, various address space manipulation syscalls)&lt;/li&gt;
&lt;li&gt;It calls these shared libraries to do name lookup (system calls: you can&amp;rsquo;t tell anymore)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is additionally the problem that at the system call layer, DNS
lookups are indistinguishable from other UDP socket operations, so
allow-listing DNS will probably allow other UDP traffic as well.&lt;/p&gt;
&lt;p&gt;So, to summarize: Attempting to implement a &lt;code&gt;pledge()&lt;/code&gt; like call with
seccomp-bpf and independent of a specific libc is an inherently
brittle approach, which &lt;strong&gt;involves keeping up-to-date lists of system
calls on different kernel versions and architectures and their use by
different libcs&lt;/strong&gt;. The complexity and feature-richness of glibc
(particularly libnss) makes this particularly difficult. Any
libc-independent &lt;code&gt;pledge()&lt;/code&gt; library would need to get updated in sync
with glibc updates, or it would run the risk that glibc starts using a
syscall that it doesn&amp;rsquo;t allow-list, breaking the programs that use it.&lt;/p&gt;
&lt;p&gt;Justine Tunney&amp;rsquo;s &lt;code&gt;pledge()&lt;/code&gt; implementation works around these problems
by (a) only supporting her own, simpler, libc implementation, and (b)
only supporting the x86-64 architecture. I&amp;rsquo;m really happy to see that
this works well together, but I&amp;rsquo;m afraid it&amp;rsquo;s a mistake to think this
implementation can be &amp;ldquo;ported&amp;rdquo; to glibc which is used for the bulk of
Linux distributions.&lt;/p&gt;
&lt;h2 id=&#34;restricting-by-file-path&#34;&gt;Restricting by file path&lt;/h2&gt;
&lt;p&gt;In OpenBSD, &lt;code&gt;pledge()&lt;/code&gt; was always path-aware, until they moved that
part into the separate &lt;code&gt;unveil()&lt;/code&gt; call.&lt;/p&gt;
&lt;p&gt;Seccomp-bpf can only filter syscalls by their direct arguments, so the
filter can see the value of the pointer to the path name, but not the
path name itself in the memory referenced by that pointer.&lt;/p&gt;
&lt;p&gt;There are more advanced techniques to inspect pointer memory, but
using these safely involves separate supervisor processes or more
complicated constrained ways to control what processes do &amp;ndash; you need
to take security very seriously pull that off, and doesn&amp;rsquo;t map to a
call to a single C function like &lt;code&gt;pledge()&lt;/code&gt; anymore.&lt;/p&gt;
&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;
&lt;p&gt;Unprivileged sandboxing continues to be difficult on Linux, for the
moment, and it&amp;rsquo;s no surprise that the main users of seccomp-bpf are
either dedicated sandboxing or containerization tools, or projects
where security is a major focus, like web browsers, OpenSSH or Tor.
But we should not give up yet. :)&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://landlock.io/&#34;&gt;Landlock LSM&lt;/a&gt; offers a better approach for
unprivileged sandboxing, although it can&amp;rsquo;t currently restrict the same
number of operations yet as seccomp-bpf can.  Landlock can
solve the above problems, because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Landlock filters security-sensitive operations at the point when
these operations are done in the kernel, not at the system call
layer. This makes it architecture independent and removes the
need to keep up-to-date lists of system calls.&lt;/li&gt;
&lt;li&gt;Landlock can easily filter on file paths and other relevant
in-memory properties that can not be observed by seccomp-bpf at the
system call interface.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to try it out, Landlock is already enabled on some Linux
distributions (i.e. Arch Linux). A simple call to Landlock (using the
Go library) is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;err := landlock.V1.BestEffort().RestrictPaths(
    landlock.RODirs(&amp;quot;/usr&amp;quot;, &amp;quot;/bin&amp;quot;),
    landlock.RWDirs(&amp;quot;/tmp&amp;quot;),
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Some further links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://landlock.io&#34;&gt;https://landlock.io&lt;/a&gt;&lt;/li&gt;
&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;
&lt;/ul&gt;
&lt;h2 id=&#34;summary&#34;&gt;Summary&lt;/h2&gt;
&lt;p&gt;As shown above, seccomp-bpf makes it more difficult than necessary to
sandbox processes. It is available on a wide range of Linux
distributions, but it&amp;rsquo;s currently not practical to use for the bulk of
software linked to glibc, and it&amp;rsquo;s not possible to restrict operations
by file path in BPF.&lt;/p&gt;
&lt;p&gt;Landlock is not rolled out to all Linux distributions yet, and it
still has some known gaps in its current version, but it has a
significantly simpler API and a much simpler implementation in the
kernel than what would be required in userspace to work around the
problems of seccomp-bpf.&lt;/p&gt;
&lt;p&gt;And simplicity is a great property for security features to have. I
can wholeheartedly recommend having a look at it.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>XKB With Sway</title>
      <link>https://blog.gnoack.org/post/xkb-with-sway/</link>
      <pubDate>Thu, 02 Dec 2021 18:24:17 +0100</pubDate>
      
      <guid>https://blog.gnoack.org/post/xkb-with-sway/</guid>
      <description>&lt;p&gt;This explains how to configure multiple keyboards in Sway, and how to
use advanced configuration when regular &lt;code&gt;xkb_options&lt;/code&gt; are not enough.&lt;/p&gt;
&lt;h2 id=&#34;sway-configuration&#34;&gt;Sway configuration&lt;/h2&gt;
&lt;p&gt;Luckily, Sway has great support for multiple keyboards with different
layouts, so it nicely adjusts to whatever keyboard you have plugged in
or can use separate configurations for a physical keyboard and the
laptop keyboard.&lt;/p&gt;
&lt;p&gt;First, identify the identifiers for the keyboards you have plugged in,
using the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ swaymsg -t get_inputs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Look for the lines starting with &lt;code&gt;Identifier:&lt;/code&gt; for the device you&amp;rsquo;re
interested in.&lt;/p&gt;
&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;
&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;input &amp;quot;1278:32:PFU_Limited_HHKB-Classic&amp;quot; {
	xkb_layout &amp;quot;us&amp;quot;
	xkb_model &amp;quot;hhk&amp;quot;
	xkb_options &amp;quot;compose:ralt&amp;quot;
	xkb_capslock &amp;quot;disabled&amp;quot;
}

input &amp;quot;1133:49948:Logitech_USB_Keyboard&amp;quot; {
	xkb_file &amp;quot;.xkb/keymap/logitech&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The example above lists a HHKB (&amp;ldquo;Happy Hacking&amp;rdquo;) keyboard where right
Alt acts as the Compose key. More options are documented in the man
pages &lt;a href=&#34;https://manned.org/sway-input.5&#34;&gt;sway-input(5)&lt;/a&gt; as well as
&lt;a href=&#34;https://manned.org/xkeyboard-config.7&#34;&gt;xkeyboard-config(7)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the case where the existing XKB options are not sufficient, you
need to refer to a separate XKB configuration file, as described below.&lt;/p&gt;
&lt;h2 id=&#34;xkb-configuration&#34;&gt;XKB configuration&lt;/h2&gt;
&lt;p&gt;To configure my Logitech keyboard, the plan was to have the key
mapping reasonably close to the HHKB layout.&lt;/p&gt;
&lt;p&gt;In my case, I have two files under &lt;code&gt;~/.xkb&lt;/code&gt; (the directories need to
first be created): This is the &lt;code&gt;~/.xkb/keymap/logitech&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;// Derived from `setxkbmap -print`,
// added the &amp;quot;+unixy&amp;quot; part to xkb_symbols.
xkb_keymap {
	xkb_keycodes  { include &amp;quot;evdev+aliases(qwerty)&amp;quot;	};
	xkb_types     { include &amp;quot;complete&amp;quot;	};
	xkb_compat    { include &amp;quot;complete&amp;quot;	};
	xkb_symbols   { include &amp;quot;pc+us+inet(evdev)+unixy&amp;quot;	};
	xkb_geometry  { include &amp;quot;pc(pc105)&amp;quot;	};
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This file is the output from running &lt;code&gt;setxkbmap -print&lt;/code&gt;, but adds the
&lt;code&gt;+unixy&lt;/code&gt; part to the &lt;code&gt;xkb_symbols&lt;/code&gt; section. This refers to the
&lt;code&gt;~/.xkb/symbols/unixy&lt;/code&gt; file with the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;partial alphanumeric_keys
xkb_symbols &amp;quot;unixy&amp;quot; {
	// exchange backspace and backslash
	key &amp;lt;BKSL&amp;gt; {	[ BackSpace, Backspace ] };
	key &amp;lt;BKSP&amp;gt; {	[ backslash, bar ] };

	// caps is ctrl
	key &amp;lt;CAPS&amp;gt; {	[ Control_L ] };
	modifier_map Control { &amp;lt;CAPS&amp;gt; };

	// right alt is compose
	key &amp;lt;RALT&amp;gt; {	[ Multi_key ] };
};
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>Error Handling Links</title>
      <link>https://blog.gnoack.org/post/error-handling-links/</link>
      <pubDate>Fri, 10 Sep 2021 16:54:54 +0200</pubDate>
      
      <guid>https://blog.gnoack.org/post/error-handling-links/</guid>
      <description>&lt;p&gt;This is a collection of interesting literature on the subject of error
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
subject&lt;/a&gt; a while ago.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&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
Design&lt;/a&gt;&amp;rdquo;
by John Ousterhout has a significant section on error handling that
I found worth a read. It takes a slightly different angle and gives
some good examples on how to design programs in a way so that errors
cannot happen, or only happen in the right places.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&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
book&lt;/a&gt;
had the weirdest error handling mechanism: You&amp;rsquo;d call the &lt;code&gt;error:&lt;/code&gt;
method on your own object, and the interactive system pops up a
dialog. Some Smalltalk errors are recoverable in unusual ways
through the interactivity of the system - you can define methods on
the go if your program calls a method that doesn&amp;rsquo;t exist&amp;hellip; :)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Common Lisp has a &amp;ldquo;Conditions&amp;rdquo; system which is similar to exceptions
in that it propagates up the stack, but it inserts a layer in the
middle between handling (&amp;ldquo;catching&amp;rdquo;) and signaling (&amp;ldquo;raising&amp;rdquo;)
exceptions. The middle layer can define recovery strategies which
the handling layer can then choose from.&lt;/p&gt;
&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
Lisp&lt;/a&gt;&amp;rdquo; book. I cannot claim that I
managed to wrap my head around that one. The chapter is online at
&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;
. Apparently someone wrote a full book on the Common Lisp condition
system recently, but I haven&amp;rsquo;t read that.
&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;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Apart from that, the books I looked through were not very helpful. I
feel that the Ousterhout approach of explaining this is a useful one,
talking about ways to design programs so that the complications of
error handling are reduced.&lt;/p&gt;
&lt;p&gt;Other notable &amp;ldquo;error handling philosophies&amp;rdquo; I have only some links to&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&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
should never pass silently&amp;rdquo;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Midori error model
&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
experimental OS developed at Microsoft)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;My own research culminated in this article:
&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
much too academic and prescriptive approach there, and so it doesn&amp;rsquo;t
get read much. The article might be biased towards the &amp;ldquo;deployed and
monitored&amp;rdquo; kind of software.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Another thing I heard people discuss is the rule to &amp;ldquo;act on an error
in only one place&amp;rdquo;, but I failed to find a canonical source for it.
(It&amp;rsquo;s the rule that is most commonly violated if someone is logging
the same error at multiple layers in the stack, leading to log spam.)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Sandboxing with Landlock</title>
      <link>https://blog.gnoack.org/post/landlock/</link>
      <pubDate>Fri, 16 Apr 2021 14:20:09 +0200</pubDate>
      
      <guid>https://blog.gnoack.org/post/landlock/</guid>
      <description>&lt;p&gt;Linux 5.13 is going to include the unprivileged sandboxing feature
Landlock, which has been in the making for many years now.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Unprivileged&lt;/em&gt; means that you don&amp;rsquo;t need special system-level
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
Linux sandboxing mechanisms do. Philosophically speaking, you should
not need additional special privileges just to drop the privileges
that you already have.&lt;/p&gt;
&lt;div class=&#34;sidenote&#34;&gt;How it works&lt;/div&gt;
&lt;p&gt;With Landlock, processes can restrict themselves to only use a
specified set of file paths, and it lets them control which operations
are available on these paths and their subdirectories (for example
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;
&lt;p&gt;A similar sandboxing feature has been around in OpenBSD for a while
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
deck&lt;/a&gt;
&lt;a href=&#34;https://www.youtube.com/watch?v=gvmGfpMgny4&#34;&gt;and talk&lt;/a&gt; by Bob Beck
talks about the lessons learned and has examples on how to sandbox
software with it, which should translate well to Landlock.&lt;/p&gt;
&lt;div class=&#34;sidenote&#34;&gt;Download&lt;/div&gt;
&lt;p&gt;To make it easier to play with, I forked the Landlock example tool
from the kernel sources and made it compile standalone: You can get it
at
&lt;a href=&#34;https://github.com/gnoack/landlockjail&#34;&gt;https://github.com/gnoack/landlockjail&lt;/a&gt;,
or you can just download a &lt;a href=&#34;https://github.com/gnoack/landlockjail/releases/download/v1/lljail&#34;&gt;precompiled statically linked
version&lt;/a&gt;.&lt;/p&gt;
&lt;section class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;At the moment, there are still some gaps, like &lt;code&gt;stat()&lt;/code&gt;,
which can still be done even in landlocked processes. But it&amp;rsquo;s moving
in the right direction, and at least accesses to the files&#39; contents
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;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
    </item>
    
    <item>
      <title>Writing Tests in Go</title>
      <link>https://blog.gnoack.org/post/go-tests/</link>
      <pubDate>Wed, 10 Feb 2021 22:00:06 +0100</pubDate>
      
      <guid>https://blog.gnoack.org/post/go-tests/</guid>
      <description>&lt;div class=&#34;sidenote&#34;&gt;Tests should be correct by inspection&lt;/div&gt;
Tests require a different approach than normal code. We don&#39;t have
tests for tests, so tests need to be correct by inspection -- and the
main technique to achieve this is to get rid of the generality of the
production code, and exercise only very narrow and specific scenarios.
&lt;h1 id=&#34;decide-what-test-to-write&#34;&gt;Decide what test to write&lt;/h1&gt;
&lt;div class=&#34;sidenote&#34;&gt;The goal of testing is to increase confidence&lt;/div&gt;
A test&#39;s purpose is to increase the confidence that you have in your
program&#39;s correctness. The next test to write is the test that
promises the highest ratio of additional confidence for the work
required to write it.
&lt;h2 id=&#34;do-test-all-your-business-decisions&#34;&gt;Do test all your business decisions&lt;/h2&gt;
&lt;p&gt;Test all your code that is testable. Prioritize testing the code that
(a) &lt;strong&gt;is important to work correctly&lt;/strong&gt; (where confidence needs to be
high) or (b) &lt;strong&gt;has become too complicated&lt;/strong&gt; (where confidence has
dropped too low).&lt;/p&gt;
&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;
&lt;div class=&#34;sidenote&#34;&gt;Controversial part ahead!&lt;/div&gt;
Sometimes, production code will do I/O or other side effects that are
hard to simulate reproducably in a test. In these cases, it can
sometimes be advisable to separate the I/O parts of the production
code out and only test the rest - the bulk of your logic. It&#39;s key to
only separate out only the smallest possible part that has the side
effect, to keep as much as possible of the program testable.
&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
parts&amp;rdquo;? Well - that&amp;rsquo;s why you need to keep them tiny and stare at them
very long in a code review, to make sure they work without a test. It
sounds heretic to leave this untested, but the alternative is to keep
the I/O and other program logic together. That&amp;rsquo;ll easily make your
more regular program logic hard to test, and that&amp;rsquo;s often not worth
the trade off. After all, our goal is to increase confidence, not to
reach full line coverage.&lt;/p&gt;
&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
your program logic, such as logging and incrementing performance
counters. It&amp;rsquo;s ok to leave those untested without separating them
out - these are battle proof APIs designed for quickly adding and
removing them from your code, and they do not play a role for your
programs correctness. It would give you little additional confidence
to test them.&lt;/p&gt;
&lt;h1 id=&#34;structure-your-tests-into-givenwhenthen&#34;&gt;Structure your tests into Given/When/Then&lt;/h1&gt;
&lt;div class=&#34;sidenote&#34;&gt;Stick to the three test phases!&lt;/div&gt;
&lt;p&gt;Stick with the setup/exercise/verify style of tests. Some people call
this also
&lt;a href=&#34;https://martinfowler.com/bliki/GivenWhenThen.html&#34;&gt;Given/When/Then&lt;/a&gt;
or the &lt;a href=&#34;http://xunitpatterns.com/Four%20Phase%20Test.html&#34;&gt;&amp;ldquo;Four Phase
test&amp;rdquo;&lt;/a&gt; (counting
tear-down as separate phase).&lt;/p&gt;
&lt;p&gt;It does not matter what you call this pattern, but &amp;ldquo;Given/When/Then&amp;rdquo;
tends to read nice in comments. Delimiting the section explicitly with
comments is optional, but serves another useful purpose: You cannot
use helper functions that span multiple of these purposes. (Those
helper functions would be bad style.)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;func TestSpellOut(t *testing.T) {
  // Given
  s := speller.New(&amp;quot;en&amp;quot;)

  // When
  got := s.SpellOut(42)

  // Then
  want := &amp;quot;forty-two&amp;quot;
  if got != want {
    t.Errorf(&amp;quot;SpellOut(%q); got %q, want %q&amp;quot;, 42, got, want)
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&#34;test-helpers&#34;&gt;Test helpers&lt;/h1&gt;
&lt;p&gt;Test helper functions should be the primary way to share functionality
between tests.&lt;/p&gt;
&lt;div class=&#34;sidenote&#34;&gt;Each helper serves only one of the test phases&lt;/div&gt;
Make sure that each test helper helps with only one of the test
phases: setup, exercise or verify.
&lt;p&gt;In particular, resist the temptation to extract the whole test into a
helper method, so that you can call it with differing parameters. The
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
tests&lt;/a&gt;
and
&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;
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;
&lt;h2 id=&#34;setup-helpers&#34;&gt;Setup helpers&lt;/h2&gt;
&lt;div class=&#34;sidenote&#34;&gt;The checklist for setup helpers&lt;/div&gt;
A setup helper is called from a test&#39;s setup phase and should have the
following properties:
&lt;ul&gt;
&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;
&lt;li&gt;It calls &lt;code&gt;t.Helper()&lt;/code&gt; at the start.&lt;/li&gt;
&lt;li&gt;It may not return an error, but will call &lt;code&gt;t.Fatal()&lt;/code&gt; on error.
&lt;ul&gt;
&lt;li&gt;It is ok to fail early in setup helpers.&lt;/li&gt;
&lt;li&gt;Tests don&amp;rsquo;t need to check errors manually, making them easier to read.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If it sets up state that needs to be undone after the test, it calls
&lt;a href=&#34;https://blog.gnoack.org/post/go-testing-cleanup&#34;&gt;&lt;code&gt;t.Cleanup()&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is a helper method for setting up a &lt;code&gt;Speller&lt;/code&gt; object from the
previous example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;func setUpSpeller(t testing.TB, path string) speller.Speller {
  t.Helper()

  s, err := speller.Load(path)
  if err != nil {
    t.Fatalf(&amp;quot;Could not set up speller: speller.Load(%q): %v&amp;quot;,
             path, err)
  }

  t.Cleanup(s.Close)
  return s
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;exercise-helpers&#34;&gt;Exercise helpers&lt;/h2&gt;
&lt;div class=&#34;sidenote&#34;&gt;Don&#39;t.&lt;/div&gt;
Only introduce helpers for the test&#39;s execute phase if the invocation
is unbearable to read.
&lt;p&gt;It&amp;rsquo;s good practice to exercise the component under test directly
without such a helper. Using the component directly is a good test for
its API&amp;rsquo;s usability and will often uncover small possibilities for API
improvements in the process.&lt;/p&gt;
&lt;h2 id=&#34;verification-helpers&#34;&gt;Verification helpers&lt;/h2&gt;
&lt;div class=&#34;sidenote&#34;&gt;Alternatives to assertion libraries&lt;/div&gt;
Common Go style discourages the use of assertion helper libraries,
which are common in most other languages.
&lt;p&gt;While I don&amp;rsquo;t necessarily agree with that, the next best thing you can
do within the bounds of this style is to extract helpers that do the
necessary comparisons for you, if necessary. The ground rule I use is:
The &lt;code&gt;if&lt;/code&gt; should be part of the top-level test function, but the
condition in that check can call the helper.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;These helpers do not need to have &lt;code&gt;testing.TB&lt;/code&gt; passed in - they are
just regular utility functions.&lt;/li&gt;
&lt;li&gt;They should probably return a boolean, or other object representing
the result of the check (like
&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;
&lt;/ul&gt;
&lt;h1 id=&#34;general-advice-on-writing-tests&#34;&gt;General advice on writing tests&lt;/h1&gt;
&lt;p&gt;A lot of general advice from other testing frameworks is applicable to
Go too.&lt;/p&gt;
&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;
&lt;p&gt;Each test should exercise a specific and narrow scenario. There should
be little overlap between tests. Any bug introduced in the code should
ideally only break a single test, which has narrow focus and is
related to the broken functionality.&lt;/p&gt;
&lt;h3 id=&#34;start-with-the-assertion&#34;&gt;Start with the assertion&lt;/h3&gt;
&lt;p&gt;Start writing tests with the assertion, and work from there upwards by
filling out the missing variables that aren&amp;rsquo;t defined yet. This
approach helps me to focus each test around one specific and narrow
behaviour that I want to test.&lt;/p&gt;
&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;
&lt;p&gt;With simple functions with inputs, outputs and errors, I like to have
one main test for the happy path, plus one for each error, whose test
input is based on the one for the happy path, with a modification.&lt;/p&gt;
&lt;p&gt;See my article on &lt;a href=&#34;https://blog.gnoack.org/post/base_fixture&#34;&gt;Shared base fixtures&lt;/a&gt; for examples.&lt;/p&gt;
&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;
&lt;p&gt;If you don&amp;rsquo;t know what &lt;code&gt;TestMain&lt;/code&gt; is, good!&lt;/p&gt;
&lt;p&gt;&lt;code&gt;TestMain&lt;/code&gt; is a way to share common test setup and teardown between
multiple test cases, without them calling a setup helper explicitly.
In most cases, this is better done with a setup helper function as
described above.&lt;/p&gt;
&lt;p&gt;There is one case where &lt;code&gt;TestMain&lt;/code&gt; is acceptable, which is the case
where the test setup is so expensive to run that it will be
significantly faster to only do it once.&lt;/p&gt;
&lt;section class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;&lt;code&gt;t.Run()&lt;/code&gt; is a way of structuring your test output, but it&amp;rsquo;ll
also make sure that subtests can cancel with &lt;code&gt;t.Fatal()&lt;/code&gt;, without
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;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;&lt;code&gt;testing.TB&lt;/code&gt; is an interface for the common methods in
&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
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;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
    </item>
    
    <item>
      <title>Don&#39;t check emptyness before loops</title>
      <link>https://blog.gnoack.org/post/dont-check-emptyness-before-loops/</link>
      <pubDate>Tue, 06 Oct 2020 07:12:04 +0200</pubDate>
      
      <guid>https://blog.gnoack.org/post/dont-check-emptyness-before-loops/</guid>
      <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;
&lt;p&gt;Don&amp;rsquo;t do this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-java&#34;&gt;if (!stuff.empty()) {
  for (Item item : stuff) {
    // ...
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do this instead:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-java&#34;&gt;for (Item item : stuff) {
  // ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Shorter&lt;/li&gt;
&lt;li&gt;Less nesting&lt;/li&gt;
&lt;li&gt;Same performance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I used to do this too at some point in the past, because I thought
this would have performance benefits, but in reality, the performance
benefit is hardly measurable and generally falls into the category
&lt;a href=&#34;https://wiki.c2.com/?PrematureOptimization&#34;&gt;&amp;ldquo;premature optimization&amp;rdquo;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Even if there is a little extra code happening between the &lt;code&gt;if&lt;/code&gt; and
the &lt;code&gt;for&lt;/code&gt;, the performance impact needs to be significant for this to
make a difference in most cases, and it&amp;rsquo;s probably not worth the
additional code convolution.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Go-style coroutines in the FN language</title>
      <link>https://blog.gnoack.org/post/coroutines-in-fn/</link>
      <pubDate>Mon, 14 Sep 2020 11:15:00 +0100</pubDate>
      
      <guid>https://blog.gnoack.org/post/coroutines-in-fn/</guid>
      <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
single-threaded language, but with its built-in stack-inspection
capabilities, it&amp;rsquo;s easy to build coroutines on top.&lt;/p&gt;
&lt;p&gt;The
&lt;a href=&#34;https://github.com/gnoack/fn/blob/master/examples/threads.fn#L29&#34;&gt;implementation&lt;/a&gt;
only has about 20 lines of code, including comments. This article
contains a simplified implementation in-line. In only rewrote some
comments to make more sense in context, and removed confusing
technicalities like &lt;code&gt;fn&lt;/code&gt;&amp;rsquo;s custom method call syntax, the use of
&lt;code&gt;dynamic-wind&lt;/code&gt; and remarks about tail calls.&lt;/p&gt;
&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;In most programming languages, the call stack is a chain of stack
frames which ends in the program&amp;rsquo;s entry point.&lt;/p&gt;
&lt;figure&gt;
  &lt;div id=&#39;pikchr-0&#39; class=&#39;pikchr&#39;&gt;
&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:335px&#39;&gt;
&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 335.463 180.386&#34;&gt;
&lt;path d=&#34;M129,178L328,178L328,22L129,22Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M2,178L58,178L58,149L2,149Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;30&#34; y=&#34;164&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;bar&lt;/text&gt;
&lt;polygon points=&#34;30,110 34,121 26,121&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M30,149L30,115&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;30&#34; y=&#34;120&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; font-size=&#34;80%&#34; transform=&#34;rotate(-90 30,130)&#34; dominant-baseline=&#34;central&#34;&gt;caller&lt;/text&gt;
&lt;path d=&#34;M2,110L58,110L58,81L2,81Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;30&#34; y=&#34;96&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;foo&lt;/text&gt;
&lt;polygon points=&#34;30,42 34,53 26,53&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M30,81L30,47&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;30&#34; y=&#34;52&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; font-size=&#34;80%&#34; transform=&#34;rotate(-90 30,62)&#34; dominant-baseline=&#34;central&#34;&gt;caller&lt;/text&gt;
&lt;path d=&#34;M2,42L58,42L58,13L2,13Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;30&#34; y=&#34;27&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;main&lt;/text&gt;
&lt;path d=&#34;M143,107L313,107L313,36L143,36Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;228&#34; y=&#34;51&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;information to&lt;/text&gt;
&lt;text x=&#34;228&#34; y=&#34;71&#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;
&lt;text x=&#34;228&#34; y=&#34;92&#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;
&lt;path d=&#34;M143,164L313,164L313,107L143,107Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;228&#34; y=&#34;125&#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;
&lt;text x=&#34;228&#34; y=&#34;145&#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;
&lt;text x=&#34;228&#34; y=&#34;12&#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;
&lt;path d=&#34;M58,178L129,178&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;
&lt;path d=&#34;M58,149L129,22&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:2.16,7.2;&#34; /&gt;
&lt;/svg&gt;
&lt;/div&gt;
&lt;/div&gt;

  &lt;figcaption&gt;&lt;p&gt;A conventional call stack&lt;/p&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;div class=&#34;sidenote&#34;&gt;
Stack frames are on the heap in fn.
&lt;/div&gt;
&lt;p&gt;In the case of C, this call stack is a contiguous memory area, but in
&lt;em&gt;fn&lt;/em&gt;, the stack frames are actually allocated objects on the heap
which have pointers to each other. Each stack frame also stores the
information required to &lt;a href=&#34;https://github.com/gnoack/fn/blob/def2f2164f708df2980364f8f1495e94d0df8690/runtime/interpreter.c#L154&#34;&gt;resume
it&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;sidenote&#34;&gt;
Functions can get a handle on their own stack frame
&lt;/div&gt;
&lt;p&gt;Additionally, &lt;em&gt;fn&lt;/em&gt; has a natively implemented helper called
&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;.
When called, &lt;code&gt;$get-frame&lt;/code&gt; returns the caller&amp;rsquo;s own stack frame as Lisp
object which can be manipulated. You can access it from an interactive
&lt;code&gt;fn&lt;/code&gt; session as well:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-scheme&#34;&gt;fn&amp;gt; ($get-frame)
#&amp;lt;Frame () @1ff4437b5780&amp;gt;
fn&amp;gt; (frame-caller ($get-frame))
#&amp;lt;Frame () @1ff4437b97c4&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;implementation&#34;&gt;Implementation&lt;/h2&gt;
&lt;h3 id=&#34;a-queue-of-suspended-coroutines&#34;&gt;A queue of suspended coroutines&lt;/h3&gt;
&lt;p&gt;For Go-style coroutine behaviour, we keep track of a queue of call
stacks of currently suspended coroutines. A coroutine which yields
execution queues itself last, and returns into the first call stack
from that queue.&lt;/p&gt;
&lt;figure&gt;
  &lt;div id=&#39;pikchr-0&#39; class=&#39;pikchr&#39;&gt;
&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:422px&#39;&gt;
&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 422.422 210.29&#34;&gt;
&lt;text x=&#34;39&#34; y=&#34;177&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;pop out&lt;/text&gt;
&lt;text x=&#34;39&#34; y=&#34;198&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;(resume)&lt;/text&gt;
&lt;polygon points=&#34;82,187 94,183 94,192&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M88,187L116,187&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M116,202L162,202L162,173L116,173Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;polygon points=&#34;139,145 143,156 135,156&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M139,173L139,151&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M122,145L156,145L156,122L122,122Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;polygon points=&#34;139,94 143,105 135,105&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M139,122L139,100&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M122,94L156,94L156,71L122,71Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;polygon points=&#34;139,43 143,54 135,54&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M139,71L139,49&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M122,43L156,43L156,20L122,20Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;122&#34; y=&#34;73&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; transform=&#34;rotate(-90 122,83)&#34; dominant-baseline=&#34;central&#34;&gt;next to be resumed&lt;/text&gt;
&lt;path d=&#34;M162,202L207,202L207,173L162,173Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;polygon points=&#34;184,145 189,156 180,156&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M184,173L184,151&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M167,145L201,145L201,122L167,122Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;polygon points=&#34;184,94 189,105 180,105&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M184,122L184,100&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M167,94L201,94L201,71L167,71Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M207,202L252,202L252,173L207,173Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;polygon points=&#34;230,145 234,156 225,156&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M230,173L230,151&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M213,145L247,145L247,122L213,122Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;polygon points=&#34;230,94 234,105 225,105&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M230,122L230,100&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M213,94L247,94L247,71L213,71Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;polygon points=&#34;230,43 234,54 225,54&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M230,71L230,49&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M213,43L247,43L247,20L213,20Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M252,202L298,202L298,173L252,173Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;polygon points=&#34;275,145 279,156 271,156&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M275,173L275,151&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M258,145L292,145L292,122L258,122Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;polygon points=&#34;275,94 279,105 271,105&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M275,122L275,100&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M258,94L292,94L292,71L258,71Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;polygon points=&#34;298,187 309,183 309,192&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M304,187L332,187&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;379&#34; y=&#34;177&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;push in&lt;/text&gt;
&lt;text x=&#34;379&#34; y=&#34;198&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;(suspend)&lt;/text&gt;
&lt;/svg&gt;
&lt;/div&gt;
&lt;/div&gt;

  &lt;figcaption&gt;&lt;p&gt;A queue of suspended call stacks&lt;/p&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;div class=&#34;sidenote&#34;&gt;
Starting new coroutines
&lt;/div&gt;
&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
its caller and itself becomes the entry point for the new coroutine
which immediately executes. The helper function &lt;code&gt;thread-die!&lt;/code&gt;
unschedules the current thread from execution by scheduling another
coroutine without adding itself back to the queue.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-scheme&#34;&gt;(defn thread-new! (thunk)
  ;; Suspend current call stack.
  (queue-push! *thread-queue* (frame-caller ($get-frame)))
  ;; Make sure we don&#39;t accidentally
  (set-frame-caller! ($get-frame) &#39;*should-never-be-used*)
  ;; Call thunk, then call thread-die!.
  (thunk)
  (thread-die!))

(defn thread-die! ()
  (set-frame-caller! ($get-frame)
                     (queue-pop! *thread-queue*))
  nil)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;switching-between-coroutines&#34;&gt;Switching between coroutines&lt;/h3&gt;
&lt;div class=&#34;sidenote&#34;&gt;
In some languages, &lt;tt&gt;next-thread!&lt;/tt&gt; would be called &lt;tt&gt;yield&lt;/tt&gt;
&lt;/div&gt;
&lt;p&gt;To switch between coroutines, all you need to do is to have &lt;em&gt;multiple
call stacks&lt;/em&gt; and switch between them. In &lt;em&gt;fn&lt;/em&gt;, this is done in the
&lt;code&gt;next-thread!&lt;/code&gt; function. &lt;code&gt;next-thread!&lt;/code&gt;, when called, will swizzle out
the calling stack frame stored in its own stack frame. That way, the
function can return into a different call stack than the one it was
invoked from.&lt;/p&gt;
&lt;figure&gt;
  &lt;div id=&#39;pikchr-0&#39; class=&#39;pikchr&#39;&gt;
&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:185px&#39;&gt;
&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 185.737 219.753&#34;&gt;
&lt;path d=&#34;M24,217L115,217L115,189L24,189Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;70&#34; y=&#34;203&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;next-thread!&lt;/text&gt;
&lt;polygon points=&#34;30,143 34,155 26,155&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M58,189 L 44,180 Q 30,172 30,160 L 30,149&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M2,143L58,143L58,115L2,115Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;polygon points=&#34;30,87 34,98 26,98&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M30,115L30,92&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M2,87L58,87L58,58L2,58Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;polygon points=&#34;30,30 34,42 26,42&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M30,58L30,36&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M2,30L58,30L58,2L2,2Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M16,166L56,166&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(255,0,0);&#34; /&gt;
&lt;path d=&#34;M16,177L56,155&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(255,0,0);&#34; /&gt;
&lt;text x=&#34;56&#34; y=&#34;155&#34; text-anchor=&#34;start&#34; fill=&#34;rgb(255,0,0)&#34; dominant-baseline=&#34;central&#34;&gt; 1.&lt;/text&gt;
&lt;polygon points=&#34;155,143 159,155 150,155&#34; style=&#34;fill:rgb(60,179,113)&#34;/&gt;
&lt;path d=&#34;M92,189 L 124,177 Q 155,166 155,158 L 155,149&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(60,179,113);stroke-dasharray:7.2,7.2;&#34; /&gt;
&lt;text x=&#34;124&#34; y=&#34;154&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(60,179,113)&#34; dominant-baseline=&#34;central&#34;&gt;2.&lt;/text&gt;
&lt;path d=&#34;M126,143L183,143L183,115L126,115Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;polygon points=&#34;155,87 159,98 150,98&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M155,115L155,92&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M126,87L183,87L183,58L126,58Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;polygon points=&#34;155,30 159,42 150,42&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M155,58L155,36&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M126,30L183,30L183,2L126,2Z&#34;  style=&#34;fill:rgb(173,216,230);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;/svg&gt;
&lt;/div&gt;
&lt;/div&gt;

  &lt;figcaption&gt;&lt;p&gt;next-thread! returns into a different call stack than it was called from&lt;/p&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;code&gt;next-thread!&lt;/code&gt; is implemented as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-scheme&#34;&gt;(defn next-thread! ()
  ;; Push our own frame&#39;s caller onto the queue.
  (queue-push! *thread-queue* (frame-caller ($get-frame)))
  ;; Remove a suspended stack frame from the queue,
  ;; and set it as our own caller, so we&#39;ll return to it.
  (set-frame-caller! ($get-frame)
                     (queue-pop! *thread-queue*))
  nil)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;caveats-about-tail-calls&#34;&gt;Caveats about tail calls&lt;/h3&gt;
&lt;p&gt;Manipulating your own stack frame leads to a simple and short
implementation, but the devil is in the details.&lt;/p&gt;
&lt;p&gt;In particular, in languages with implicit and automatic tail calls, an
invocation such as &lt;code&gt;(set-frame-caller! ($get-frame) ...)&lt;/code&gt; cannot be
put at the end of a function, of you would manipulate the caller of a
function that won&amp;rsquo;t ever return again. To work around this problem,
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;
explicitly at the end, so that &lt;code&gt;set-frame-caller!&lt;/code&gt; does not get
invoked with a tail call.&lt;/p&gt;
&lt;p&gt;The full coroutine implementation is in the &lt;code&gt;fn&lt;/code&gt; repository in
&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;
</description>
    </item>
    
    <item>
      <title>Rendering drawings with tuhirender</title>
      <link>https://blog.gnoack.org/post/tuhirender/</link>
      <pubDate>Mon, 06 Jul 2020 00:04:10 +0200</pubDate>
      
      <guid>https://blog.gnoack.org/post/tuhirender/</guid>
      <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
Slate&lt;/a&gt;
tablet and &lt;a href=&#34;https://github.com/tuhiproject/tuhi&#34;&gt;Tuhi&lt;/a&gt;. It was good
fun to take Tuhi&amp;rsquo;s drawing data and create my own renderer
&lt;a href=&#34;https://github.com/gnoack/tuhirender&#34;&gt;tuhirender&lt;/a&gt;, which can be used
from the command line to produce some more advanced effects and tune
more of the rendering knobs.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tuhirender&lt;/code&gt; replaces Tuhi&amp;rsquo;s own renderer by building on Tuhi&amp;rsquo;s
JSON-based output format for line coordinates and pen pressure data.&lt;/p&gt;
&lt;h2 id=&#34;basic-invocation&#34;&gt;Basic invocation&lt;/h2&gt;
&lt;p&gt;The basic invocation is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tuhirender -width 200 -fit -o out.png &amp;lt; in/1593622352.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All parameters are in principle optional, but this invocation shows
the most commonly used options. &lt;code&gt;-width&lt;/code&gt; specifies the desired output
width in pixels.&lt;/p&gt;
&lt;h2 id=&#34;animate-a-drawing&#34;&gt;Animate a drawing&lt;/h2&gt;
&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;
&lt;figure&gt;&lt;img src=&#34;drawing.gif&#34;
         alt=&#34;An animated drawing&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;An animated drawing&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id=&#34;simplify-line-segments&#34;&gt;Simplify line segments.&lt;/h2&gt;
&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
previuos post on the topic: &lt;a href=&#34;https://blog.gnoack.org/post/path-simplification-lib/&#34;&gt;Go: Path simplification
library&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://blog.gnoack.org/post/path-simplification-lib/hippie.png&#34;
         alt=&#34;Original and simplified version side-by-side&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Original and simplified version side-by-side&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This picture is a bit of an extreme example to demonstrate the
simplification. When tweaking the parameters a bit, the simplification
is less visible. At some point, I might be able to use this for
outputting vector graphics at reduced file size and acceptable quality
loss.&lt;/p&gt;
&lt;h2 id=&#34;some-sample-pictures&#34;&gt;Some sample pictures&lt;/h2&gt;
&lt;figure&gt;&lt;img src=&#34;winged-victory-of-samothrace.png&#34;
         alt=&#34;A bigger picture: Winged Victory of Samothrace&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;A bigger picture: Winged Victory of Samothrace&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This is the biggest picture I&amp;rsquo;ve drawn so far with the tablet; I&amp;rsquo;m
happy with how it turned out. The hatching renders nicely and produces
the desired shades.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;sausage.png&#34;
         alt=&#34;A cartoon drawing: A man, a dog and a sausage&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;A cartoon drawing: A man, a dog and a sausage&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This cartoon drawing is simpler and has a bigger zoom, so it&amp;rsquo;s easier
to see how the change in pen pressure is rendered.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;gopher.png&#34;
         alt=&#34;A gopher&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;A gopher&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The gopher picture has a lot of nuanced Pen pressure, and arguably it
looked slightly better on paper. At the moment, &lt;code&gt;tuhirender&lt;/code&gt; renders
pen pressure by modifying the line width on the go. I suspect that
changing the line opacity might be better, but I&amp;rsquo;m still looking for
an elegant algorithm to fix up the artifacts between line segments
when doing that.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Go: Test Cleanup in Go 1.14</title>
      <link>https://blog.gnoack.org/post/go-testing-cleanup/</link>
      <pubDate>Thu, 14 May 2020 09:26:41 +0200</pubDate>
      
      <guid>https://blog.gnoack.org/post/go-testing-cleanup/</guid>
      <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;
function schedules defer-like work to be done after the current test.
This makes it possible to write very comfortable setup helper
functions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-golang&#34;&gt;func SetUpFrobnicator(t *testing.T) *frob.Frobnicator {
    t.Helper()

    f := frob.New()    // Do setup.
    t.Cleanup(f.Close) // Schedule cleanup for later.
    return f
}

func TestFoobar(t *testing.T) {
    f := SetUpFrobnicator(t)

    // (Run the test itself, using f.)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Previously, presumably the most idiomatic thing would have been to
return a &amp;ldquo;cancel&amp;rdquo; callback from the helper function and rely on the
test to defer it.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m almost a bit surprised that the Go test framework offers this
now - otherwise, compared to other languages, Go&amp;rsquo;s test code is very
similar in style to production code (e.g. it doesn&amp;rsquo;t even have assert
functions).&lt;/p&gt;
&lt;p&gt;Related articles on this blog:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.gnoack.org/post/setup-cleanup/&#34;&gt;The Setup-Cleanup problem&lt;/a&gt; in different programming languages&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.gnoack.org/post/base_fixture/&#34;&gt;Shared Base Fixture&lt;/a&gt; in unit tests&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Why Software Design?</title>
      <link>https://blog.gnoack.org/post/why-software-design/</link>
      <pubDate>Wed, 13 May 2020 21:10:10 +0200</pubDate>
      
      <guid>https://blog.gnoack.org/post/why-software-design/</guid>
      <description>&lt;p&gt;The main technique in software design is this: You look at the
entirety of your system and you decompose it into pieces that are more
manageable and have clear interfaces. This approach is usually
referred to as &lt;em&gt;modularization&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;But what&amp;rsquo;s the point of investing such an effort if in the end only
the externally visible properties of a software matter?&lt;/p&gt;
&lt;p&gt;In his classic paper “On the Criteria To Be Used in Decomposing
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
rationale:&lt;/p&gt;
&lt;figure class=&#34;alignright&#34;&gt;&lt;img src=&#34;https://blog.gnoack.org/post/why-software-design/images/parnas.png&#34;
         alt=&#34;David Parnas&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;David Parnas&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;blockquote&gt;
&lt;p&gt;The benefits expected of modular
programming are (1) &lt;em&gt;managerial&lt;/em&gt; &amp;ndash; development time should be
shortened because separate groups would work on each module with
little need for communication; (2) &lt;em&gt;product flexibility&lt;/em&gt; &amp;ndash; it
should be possible to make drastic changes to one module without a
need to change others; (3) &lt;em&gt;comprehensibility&lt;/em&gt; &amp;ndash; it should be
possible to study the system one module at a time. The whole system
can therefore be better designed because it is better understood.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To paraphrase this in today&amp;rsquo;s terminology, the benefits of modularization are:&lt;/p&gt;
&lt;p&gt;(1) &lt;strong&gt;To enable independent work&lt;/strong&gt; on different modules through clear
interfaces which reduce communication overhead.&lt;/p&gt;
&lt;div class=&#34;sidenote&#34;&gt;Conway&#39;s Law&lt;/div&gt;
&lt;p&gt;A more sarcastic take on cross-team communication overhead is
&lt;a href=&#34;https://en.wikipedia.org/wiki/Conway%27s_law&#34;&gt;Conway&amp;rsquo;s Law&lt;/a&gt;, which
states that any system designed by an organization will reflect that
organization&amp;rsquo;s communication structure.&lt;/p&gt;
&lt;p&gt;(2) &lt;strong&gt;To simplify future changes&lt;/strong&gt;, by aligning the code so that anticipated
changes are easy.&lt;/p&gt;
&lt;div class=&#34;sidenote&#34;&gt;Need to anticipate changing requirements!&lt;/div&gt;
&lt;p&gt;Changes are easy when they are contained within a module or crossing
few module boundaries. The difficulty is to &lt;em&gt;identify&lt;/em&gt; likely future
changes and lay out the system accordingly, so that they will be a fit
with the design and won&amp;rsquo;t require changes to the bigger architecture.&lt;/p&gt;
&lt;p&gt;As David Parnas says himself in the conclusion to his paper:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We propose instead that one begins with a list of difficult design
decisions or design decisions which are likely to change. Each
module is then designed to hide such a decision from the others.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Modules should not rely on each other beyond what their interfaces
guarantee, so that if you change a module, the change is contained
behind its interface and not observable to others.&lt;/p&gt;
&lt;p&gt;(3) &lt;strong&gt;To increase confidence in functionality&lt;/strong&gt;, by making reasoning
about relevant aspects easier.&lt;/p&gt;
&lt;div class=&#34;sidenote&#34;&gt;Easier reasoning for module users&lt;/div&gt;
&lt;p&gt;The key here is that the interface to each module should give a more
abstract guarantee which hides the module&amp;rsquo;s implementation details. If
the right abstraction is picked, the module&amp;rsquo;s users will be able to
reason about it in simpler terms and avoid dealing with details.&lt;/p&gt;
&lt;div class=&#34;sidenote&#34;&gt;Deep classes&lt;/div&gt;
&lt;p&gt;In a good modularization, the interface definition is small and the
contained functionality is large (a property which John Ousterhout
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
module and maximizes its benefit.&lt;/p&gt;
&lt;p&gt;Besides reasoning about behavior, a good system decomposition can
also help reasoning about other aspects. For example, it&amp;rsquo;s easier to
reason about crash resilience if different parts of the system are
deployed as separate services.&lt;/p&gt;
&lt;div class=&#34;sidenote&#34;&gt;Easier reasoning within modules&lt;/div&gt;
&lt;p&gt;Finally, a suitable system decomposition also simplifies reasoning
&lt;em&gt;within&lt;/em&gt; a module, which now has a clear contract to fulfill, as
defined by the module&amp;rsquo;s interface.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is more to be said&lt;/strong&gt; about modularization techniques and
different approaches on how to deal with the uncertainties of changing
requirements, but that has to go on a follow-up article. Subscribe to
this blog with your RSS reader to get notified of future articles.&lt;/p&gt;
&lt;section class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34; role=&#34;doc-endnote&#34;&gt;
&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
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;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34; role=&#34;doc-endnote&#34;&gt;
&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
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;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
    </item>
    
    <item>
      <title>Go: Sharing templates across multiple pages</title>
      <link>https://blog.gnoack.org/post/go_templates/</link>
      <pubDate>Sun, 03 May 2020 11:10:01 +0100</pubDate>
      
      <guid>https://blog.gnoack.org/post/go_templates/</guid>
      <description>&lt;figure&gt;&lt;img src=&#34;images/gutengopher.png&#34;
         alt=&#34;Renaissance gopher Johannes Gopherberg after inventing html/template&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Renaissance gopher Johannes Gopherberg after inventing html/template&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I&amp;rsquo;m using &lt;code&gt;html/template&lt;/code&gt; much too seldom to remember how to
properly share common template blocks across multiple pages. Today I
had to figure it out for the second time. It&amp;rsquo;s about time to document
it!&lt;/p&gt;
&lt;p&gt;The approach presented here both (1) makes it possible to share
template blocks across multiple logical pages, and (2) makes it easy
to use them using &lt;code&gt;tmpl.Execute(writer, data)&lt;/code&gt; in your HTTP handlers.&lt;/p&gt;
&lt;p&gt;In particular, with this approach, all pages share a common top-level
definition of an HTML page, as opposed to maintaining separate header
and footer templates whose opening and closing tags would need to be
kept in sync.&lt;/p&gt;
&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;
&lt;blockquote&gt;
&lt;p&gt;Clone can be used to prepare common templates and use them with
variant definitions for other templates by adding the variants after
the clone is made.&lt;/p&gt;
&lt;/blockquote&gt;
&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
for each of your pages, while making them share a common set of base
templates at the same time.&lt;/p&gt;
&lt;p&gt;The way you&amp;rsquo;d like to construct these goes something like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;images/templates.svg&#34;
         alt=&#34;Constructing separate template collections from a shared base&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Constructing separate template collections from a shared base&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;None of this is really a secret. However, before &lt;code&gt;.Clone()&lt;/code&gt; existed,
it wasn&amp;rsquo;t as easy, and it&amp;rsquo;s still easy to find a lot of outdated
advice.&lt;/p&gt;
&lt;h2 id=&#34;example&#34;&gt;Example&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s go step by step.&lt;/p&gt;
&lt;h3 id=&#34;directory-structure-for-this-example&#34;&gt;Directory structure for this example&lt;/h3&gt;
&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
&lt;code&gt;page.html&lt;/code&gt; for the top-level definition of an HTML file, a dummy
definition for the main page content in &lt;code&gt;main.html&lt;/code&gt;, as well as
various helpers that may be reused across various pages.&lt;/p&gt;
&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
minimal page just redefines &lt;code&gt;main.html&lt;/code&gt; to have the necessary content.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;images/template_instantiation.svg&#34;
         alt=&#34;The templates in foo/ override main.html from base/.&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;The templates in foo/ override main.html from base/.&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id=&#34;create-the-base-templates&#34;&gt;Create the base templates&lt;/h3&gt;
&lt;p&gt;First, define the base templates with the &lt;code&gt;page.html&lt;/code&gt; definition as
root template for all template instantiations.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;base := template.New(&amp;quot;page.html&amp;quot;)
base  = template.Must(
    base.ParseGlob(&amp;quot;templates/base/*.html&amp;quot;)))
&lt;/code&gt;&lt;/pre&gt;
&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
be used as the default template to render for all of our pages, when
it gets called through &lt;code&gt;.Execute()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;templates/base/page.html&lt;/code&gt; template defines the top-level HTML structure with
navigation bars and core site elements, and includes the main page
content &lt;code&gt;main.html&lt;/code&gt; with a &lt;code&gt;block&lt;/code&gt; action:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;...&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;!-- navigation, main site elements, etc --&amp;gt;
  {{- block &amp;quot;main.html&amp;quot; . -}}{{- end -}}
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&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;
&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;
&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;fooTmpl := template.Must(baseTmpl.Clone())
fooTmpl  = template.Must(
    fooTmpl.ParseGlob(&amp;quot;templates/foo/*.html&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We define page content in the &lt;code&gt;templates/foo/main.html&lt;/code&gt; template:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;h1&amp;gt;Hello, world!&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;This is an example template.&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;use-the-specialized-templates-in-your-handler&#34;&gt;Use the specialized templates in your handler&lt;/h3&gt;
&lt;p&gt;Finally, all that&amp;rsquo;s needed to use the specialized templates in a
handler is to just call &lt;code&gt;.Execute()&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;func handleFoo(w http.ResponseWriter, req *http.Request) {
        data := fooData{Key: &amp;quot;Value&amp;quot;}
        fooTmpl.Execute(w, data)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will automatically instantiate the collection of templates starting
from &lt;code&gt;page.html&lt;/code&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Go: Path simplification library</title>
      <link>https://blog.gnoack.org/post/path-simplification-lib/</link>
      <pubDate>Sun, 05 Apr 2020 14:13:52 +0200</pubDate>
      
      <guid>https://blog.gnoack.org/post/path-simplification-lib/</guid>
      <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
Slate&lt;/a&gt;
tablet, and had a lot of fun playing around with the output. The Linux
software for talking to that device is
&lt;a href=&#34;https://github.com/tuhiproject/tuhi&#34;&gt;Tuhi&lt;/a&gt;, which is GUI driven, but
also dumps the raw point and pressure data in JSON format into a
directory.&lt;/p&gt;
&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
simplification library&lt;/a&gt; which uses the
&lt;a href=&#34;https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm&#34;&gt;Ramer-Douglas-Peucker
algorithm&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Given a sequence of 2D points, the algorithm determines a subset of
these points so that the path drawn by these is still reasonably close
to the original. Here is an example output:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;hippie.png&#34;
         alt=&#34;Original and simplified version side-by-side&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Original and simplified version side-by-side&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I found the Ramer-Douglas-Peucker algorithm to be very clever, my
attempts to come up with my own algorithm had terrible results in
comparison.&lt;/p&gt;
&lt;p&gt;The library is here:&lt;/p&gt;
&lt;ul&gt;
&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;
&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;
&lt;/ul&gt;
&lt;p&gt;I have a vague idea to use this for simplifying diagram drawings and
straightening out imprecisely drawn shapes, replacing squiggly boxes
and arrows with properly aligned ones. I&amp;rsquo;m not sure whether I&amp;rsquo;m going
in the right direction with this approach, given that I&amp;rsquo;m not making
use of pressure data and my knowledge of the shapes I want to
recognize; we&amp;rsquo;ll see whether it&amp;rsquo;ll turn out to work.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Go: The lack of generics</title>
      <link>https://blog.gnoack.org/post/go-lack-of-generics/</link>
      <pubDate>Sun, 05 Apr 2020 11:53:00 +0200</pubDate>
      
      <guid>https://blog.gnoack.org/post/go-lack-of-generics/</guid>
      <description>&lt;p&gt;Go&amp;rsquo;s lack of generics means that people can&amp;rsquo;t overengineer in the way
they are used to, so they need to put more thought into their designs.&lt;/p&gt;
&lt;p&gt;There are some use cases where abstractions with generics are better
to the current ones (e.g. the &lt;code&gt;sort&lt;/code&gt; package), but by and large, in
other languages, people use them to build towers of abstractions which
you&amp;rsquo;ll later need to wrap your head around, which introduce conceptual
duplication (e.g. mocking and predicate frameworks) and which lead to
a fragmentation of Go style (as would be the case if people start
building abstractions to hide the &lt;code&gt;go&lt;/code&gt; keyword, like threading and
future libraries).&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The Setup-Cleanup problem</title>
      <link>https://blog.gnoack.org/post/setup-cleanup/</link>
      <pubDate>Wed, 08 Jan 2020 21:37:28 +0100</pubDate>
      
      <guid>https://blog.gnoack.org/post/setup-cleanup/</guid>
      <description>&lt;figure&gt;&lt;img src=&#34;https://blog.gnoack.org/images/cleanup.png&#34;
         alt=&#34;A picture of the Sorcerer&amp;#39;s apprentice enchanting brooms to fetch water&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;A fully automated cleanup strategy.&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This is a comparison of different programming idioms for performing
cleanup work.&lt;/p&gt;
&lt;p&gt;Common use cases where this is used include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Locking and unlocking synchronization locks.&lt;/li&gt;
&lt;li&gt;Opening and closing files.&lt;/li&gt;
&lt;li&gt;Canceling asynchronous operations that aren&amp;rsquo;t needed any more.&lt;/li&gt;
&lt;li&gt;Allocation and deallocation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;a-naive-solution-cluttered-cleanups&#34;&gt;A naive solution: Cluttered cleanups&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&#34;language-c&#34;&gt;int frobnicate() {
        set_up();

        int err = foo();
        if (err) {
                clean_up();  // &amp;lt;-- 1.
                return err;
        }

        if (!bar()) {
                clean_up();  // &amp;lt;-- 2.
                return ERROR_ACCESS;
        }

        baz();

        clean_up();          // &amp;lt;-- 3.
        return SUCCESS;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are now three places where &lt;code&gt;clean_up()&lt;/code&gt; is being called (Code
duplication), and they are all far away from the call to &lt;code&gt;set_up()&lt;/code&gt;.
When the code changes a bit, it&amp;rsquo;s easy to miss one and introduce
cleanup issues. This is not a well-maintainable approach.&lt;/p&gt;
&lt;h2 id=&#34;linux-kernel-style-c&#34;&gt;Linux kernel style (C)&lt;/h2&gt;
&lt;p&gt;The Linux kernel uses gotos to coordinate a function&amp;rsquo;s cleanup:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-c&#34;&gt;int frobnicate()
{
        int rc = 0;

        set_up();

        rc = foo();
        if (rc)
                goto out;

        if (!bar()) {
                rc = EACCES;
                goto out;
        }

        baz();

out:
        clean_up();  // &amp;lt;--
        return rc;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All function exits happening after &lt;code&gt;set_up()&lt;/code&gt; need to jump to the
label where the &lt;code&gt;clean_up()&lt;/code&gt; is done.&lt;/p&gt;
&lt;p&gt;Note that this pattern can be nested: With multiple independent setup
and cleanup steps, the function ends with a sequence of multiple
cleanup operations and multiple exit labels
(&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;
&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
website&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;resource-acquisition-is-initialization-c&#34;&gt;Resource Acquisition is Initialization (C++)&lt;/h2&gt;
&lt;p&gt;In C++, setup and cleanup is frequently bound to object lifetimes,
which are deterministic there. This is an example using
&lt;a href=&#34;https://abseil.io&#34;&gt;Abseil&amp;rsquo;s&lt;/a&gt;
&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;
class:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-c++&#34;&gt;void MyClass::Frobnicate() {
  absl::MutexLock l(&amp;amp;mutex_);

  Foo();  // under lock
  Bar();  // under lock
  Baz();  // under lock
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The lifetime of the &lt;code&gt;l&lt;/code&gt; variable ends with the function scope, and
&lt;code&gt;absl::MutexLock&lt;/code&gt;&amp;rsquo;s constructor and destructor are locking and
unlocking the mutex.&lt;/p&gt;
&lt;p&gt;This pattern can also be nested. C++ guarantees that variable
destruction happens in the inverse order of construction.&lt;/p&gt;
&lt;p&gt;The RAII pattern
(&lt;a href=&#34;https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization&#34;&gt;Wikipedia&lt;/a&gt;)
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;
trait&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;To a similar extent, similar functionality to RAII is also available
in C, when using the GCC-specific
&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;
language extension. This extension lets you attach a cleanup function
to a variable scope, but the cleanup is defined in the place where the
variable is defined, not in the type.&lt;/p&gt;
&lt;blockquote class=&#34;info&#34;&gt;As readers pointed out, a newer variant of C#&amp;rsquo;s &lt;code&gt;using&lt;/code&gt; statement
implements a similar non-nested cleanup bound to variable lifetime as
well. See &lt;a href=&#34;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement&#34;&gt;the
documentation&lt;/a&gt;
comment by Morgens Heller Gabe below for examples.&lt;/blockquote&gt;

&lt;h2 id=&#34;defer-statement-go&#34;&gt;&amp;ldquo;Defer&amp;rdquo; statement (Go)&lt;/h2&gt;
&lt;p&gt;Go has a language feature for cleanup:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;func (m *MyClass) Frobnicate() {
  m.mu_.Lock()
  defer m.mu_.Unlock()

  Foo()  // under lock
  Bar()  // under lock
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;defer&lt;/code&gt; statement defers a function call until the current
function exits.&lt;/p&gt;
&lt;blockquote class=&#34;info&#34;&gt;The Zig language has syntactically similar
&lt;a href=&#34;https://ziglang.org/documentation/master/#defer&#34;&gt;&lt;code&gt;defer&lt;/code&gt;&lt;/a&gt; and
&lt;a href=&#34;https://ziglang.org/documentation/master/#errdefer&#34;&gt;&lt;code&gt;errdefer&lt;/code&gt;&lt;/a&gt;
statements. Other than in Go, Zig executes the cleanup when leaving
the current scope rather than when leaving the function.&lt;/blockquote&gt;

&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;
&lt;p&gt;Python implements a syntax which makes it easy to acquire resources
during the execution of a nested block of commands.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def readfullfile(filename):
  with open(filename) as f:
    print(&amp;quot;opened&amp;quot;, filename)
    return f.read()
&lt;/code&gt;&lt;/pre&gt;
&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
manager&lt;/a&gt;
protocol, which means that it can be used in a &lt;code&gt;with&lt;/code&gt; statement. When
the &lt;code&gt;with&lt;/code&gt;-scope exits, the cleanup functions will automatically get
invoked (e.g. to close a file).&lt;/p&gt;
&lt;p&gt;Cleanups get invoked in all cases when execution leaves the scope, no
matter whether it happens through a regular exit, an early return or
an exception.&lt;/p&gt;
&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
now support equivalent scoped statements as well:&lt;/p&gt;
&lt;ul&gt;
&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;
statement&lt;/a&gt;
(see
&lt;a href=&#34;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement&#34;&gt;documentation&lt;/a&gt;
and Mogens Heller Grabe&amp;rsquo;s comment with examples below).&lt;/li&gt;
&lt;li&gt;in Java with the
&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;
syntax. (&lt;a href=&#34;https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html&#34;&gt;examples&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In all of these cases, the used object must implement a special
interface with a cleanup method, such as &lt;code&gt;IDisposable&lt;/code&gt; in C# and
&lt;code&gt;AutoCloseable&lt;/code&gt; in Java.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;macros-lisp&#34;&gt;Macros (Lisp)&lt;/h2&gt;
&lt;p&gt;Lisp macros are used similarly as Python&amp;rsquo;s &lt;code&gt;with&lt;/code&gt; statements, but
offer more ways to shoot yourself in the foot (Example from the book
&lt;a href=&#34;http://www.gigamonkeys.com/book/files-and-file-io.html#closing-files&#34;&gt;Practical Common
Lisp&lt;/a&gt;
by Peter Seibel):&lt;/p&gt;
&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)
  (format stream &amp;quot;Some text.&amp;quot;))  ; while file is opened
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, &lt;code&gt;with-open-file&lt;/code&gt; is a macro caring about opening and closing
(&lt;a href=&#34;http://clhs.lisp.se/Body/m_w_open.htm&#34;&gt;spec&lt;/a&gt;). The user of the macro
provides a sequence of commands to be executed with the opened file
stream, e.g. &lt;code&gt;(format stream &amp;quot;Some text.&amp;quot;)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These macros are often named to start with the word &lt;code&gt;with&lt;/code&gt;, but there
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;
&lt;p&gt;From the caller perspective, this behaves similar as Python&amp;rsquo;s &lt;code&gt;with&lt;/code&gt;
statements, but they are usually expanded into a use of
&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
primitive depending on the Lisp dialect (comparable to
&lt;code&gt;try&lt;/code&gt;&amp;hellip;&lt;code&gt;finally&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id=&#34;try-finally-blocks-java-c-python-&#34;&gt;Try-Finally blocks (Java, C#, Python, &amp;hellip;)&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;try&lt;/code&gt; blocks are primarily used for catching exceptions but in many
languages they offer a &lt;code&gt;finally&lt;/code&gt; clause as well, which is guaranteed
to execute whenever the &lt;code&gt;try&lt;/code&gt; scope exits, including on early returns
and exceptions.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-java&#34;&gt;setUp();
try {
  doWork();  // between setup and cleanup
} finally {
  cleanUp();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The construct tends to lead to deeper nesting when multiple cleanups
need to be done.&lt;/p&gt;
&lt;p&gt;Some languages have &lt;code&gt;finally&lt;/code&gt;-like constructs which are independent of
exceptions, like Smalltalk with
&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;,
&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
Lisp (&lt;a href=&#34;https://wiki.c2.com/?UnwindProtect&#34;&gt;on C2 wiki&lt;/a&gt;) and
&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;
in Scheme. (Scheme has the additional complication that it needs to
deal with continuations.)&lt;/p&gt;
&lt;h2 id=&#34;todo-lists-languages-with-closures&#34;&gt;Todo lists (languages with closures)&lt;/h2&gt;
&lt;p&gt;In languages with closures or higher order functions, one way to defer
work for later is to save functions to be executed later in a list:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def frobnicate():
  todos = []

  setUp()
  todos.append(cleanUp)

  doWork()  # between setup and cleanup

  for f in todos:
    f()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One variant of this is
&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;
in Python&amp;rsquo;s &lt;code&gt;unittest&lt;/code&gt; library for deferring work to be done after the
test execution. Note that similarly to &lt;code&gt;defer&lt;/code&gt; in Go, this lets us
place the cleanup right together with the setup code, so that we can
easily keep them in sync:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;class FooTest(unittest.TestCase):
  # ...

  def test_service(self):
    srv = StartService()
    self.addCleanup(srv.Stop)

    self.assertEqual(42, srv.Invoke())  # while running
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote class=&#34;info&#34;&gt;&lt;strong&gt;Update&lt;/strong&gt;: Since version 1.14, &lt;a href=&#34;https://blog.gnoack.org/post/go-testing-cleanup/&#34;&gt;Go supports the
same&lt;/a&gt; with
&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
cleanup.&lt;/blockquote&gt;

&lt;h2 id=&#34;passing-higher-order-functions-ruby-lisp&#34;&gt;Passing higher-order functions (Ruby, Lisp?)&lt;/h2&gt;
&lt;p&gt;In Ruby, it&amp;rsquo;s common to pass down functions to other functions, as a
way of structuring control flow and also for cleanup purposes. This
invocation of
&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;
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
file and closes the file afterwards.&lt;/p&gt;
&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|
  f.puts(&amp;quot;Hello, world!&amp;quot;)  # while file is open
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This general technique is possible in all languages where passing down
higher order functions is cheap, such as Ruby and Smalltalk. Smalltalk
takes it to another level by expressing all control flow as method
invocations, including loops and &lt;code&gt;ifTrue:&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not sure to what extent the Smalltalks use higher order functions
for cleanup purposes as Ruby does. More imperative Lisps like CL
expose mostly macros to users, but these will in turn use
closure-passing unwinding primitives under the hood.&lt;/p&gt;
&lt;blockquote class=&#34;info&#34;&gt;&lt;p&gt;There is a technical twist here in that languages need special
guarantees for these so-called &lt;em&gt;downward funargs&lt;/em&gt; to be cheap.&lt;/p&gt;
&lt;p&gt;A &lt;em&gt;downward funarg&lt;/em&gt; is a higher-order function which is only passed
down the stack but does not outlive the stack frame in which it was
created. The captured variables referenced by a downward funarg can
happily stay on the stack. This is in contrast to upward funargs which
outlive their own stack frame and which require invisible heap
allocations or similar tricks in the language.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;setup-and-teardown-in-junit-xunit-&#34;&gt;setUp() and tearDown() in (JUnit, xUnit, &amp;hellip;)&lt;/h2&gt;
&lt;p&gt;In the &lt;em&gt;xUnit&lt;/em&gt; family of unit testing frameworks, tests are part of
classes which get executed by a test runner. Each test class may
optionally override &lt;code&gt;setUp()&lt;/code&gt; and &lt;code&gt;tearDown()&lt;/code&gt; hooks which get
executed around every test execution, independent of whether that test
succeeded or not.&lt;/p&gt;
&lt;p&gt;In languages which provide a sane way of cleanup, I think that
overriding the &lt;code&gt;tearDown()&lt;/code&gt; hook should not be necessary and probably
discouraged. I suspect the same is true for code in &lt;code&gt;setUp()&lt;/code&gt;, but
that is more related to ambient shared state which becomes tricky to
modify when multiple tests rely on a subset of it in implicit ways.&lt;/p&gt;
&lt;h2 id=&#34;discussion&#34;&gt;Discussion&lt;/h2&gt;
&lt;p&gt;These approaches are quite different to each other. In practice, the
programming language is often already fixed, and then only a limited
number of options exists.&lt;/p&gt;
&lt;p&gt;In general, I found that in practice it helps to have setup and
cleanup close to each other, so that it&amp;rsquo;s easy to keep them in sync.
Go&amp;rsquo;s &lt;code&gt;defer&lt;/code&gt; really shines there.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s even nicer to have them represented by the same construct as with
Python&amp;rsquo;s &lt;code&gt;with&lt;/code&gt; or C++&amp;rsquo;s RAII idiom. With these, the usage becomes
safer, but you trade that for more effort in implementing classes
that are &lt;code&gt;with&lt;/code&gt;- and RAII-enabled. (In Python, this is somewhat
mitigated with the
&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;
module.)&lt;/p&gt;
&lt;p&gt;Downward funargs are both safe, easy to use and simple to implement,
but have a little overhead. That&amp;rsquo;s fair in most scripting cases, but
wouldn&amp;rsquo;t work for the Linux kernel.&lt;/p&gt;
&lt;p&gt;In terms of reasoning about performance, the Linux kernel has the
approach where it&amp;rsquo;s most obvious what this translates to at the
machine level, but the same amount of control is usually not needed in
user space programs.&lt;/p&gt;
&lt;p&gt;At a higher level, I believe it pays off to care about symmetric setup
and cleanup steps as part of the same function wherever possible. It
makes it easier to track where setups and cleanups are done across the
codebase, and refactoring to such a design reduces state that has to
be tracked across multiple functions.&lt;/p&gt;
&lt;h2 id=&#34;update-2020-01-13&#34;&gt;Update (2020-01-13)&lt;/h2&gt;
&lt;p&gt;Thanks for all the positive feedback, particularly to everyone who
pointed out related language features:&lt;/p&gt;
&lt;ul&gt;
&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
explanation in the comments below, as well as the users
&lt;a href=&#34;https://news.ycombinator.com/item?id=21996141&#34;&gt;hateful&lt;/a&gt; and
&lt;a href=&#34;https://news.ycombinator.com/item?id=21996141&#34;&gt;niklasjansson&lt;/a&gt; on HN
who pointed out documentation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Java try-with-resources:&lt;/strong&gt;
&lt;a href=&#34;https://news.ycombinator.com/item?id=21997841&#34;&gt;cpt1138&lt;/a&gt; and
&lt;a href=&#34;https://news.ycombinator.com/item?id=21997848&#34;&gt;quantified&lt;/a&gt; on HN&lt;/li&gt;
&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;
&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;
&lt;a href=&#34;https://news.ycombinator.com/item?id=21996444&#34;&gt;apta&lt;/a&gt; on HN&lt;/li&gt;
&lt;/ul&gt;
&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;
mentioned the &lt;a href=&#34;https://wiki.haskell.org/Bracket_pattern&#34;&gt;Bracket
pattern&lt;/a&gt;, and
&lt;a href=&#34;https://news.ycombinator.com/item?id=21998455&#34;&gt;dwohnitmok&lt;/a&gt; is
mentioning linear types. Superficially this looks similar to
&lt;code&gt;dynamic-unwind&lt;/code&gt; and friends in Scheme and Lisp (see above), but my
Haskell-fu is too weak to judge it. I suspect it would be hard to
compare programming idioms between Haskell&amp;rsquo;s lazy purely functional
evaluation and imperative programs.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Mutation Testing works</title>
      <link>https://blog.gnoack.org/post/mutation-testing/</link>
      <pubDate>Mon, 30 Dec 2019 23:53:19 +0100</pubDate>
      
      <guid>https://blog.gnoack.org/post/mutation-testing/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Disclaimer: These are Google topics, but based on publicly available
resources. I&amp;rsquo;m writing this not because I get paid for it (I don&amp;rsquo;t),
but because I am truly excited about it, it&amp;rsquo;s now public, and I hope
this will find more wide-spread adoption.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Goran Petrović and Marko Ivanković have published a nice paper on the
&lt;a href=&#34;https://research.google/pubs/pub46584/&#34;&gt;&amp;ldquo;State of Mutation Testing at
Google&amp;rdquo;&lt;/a&gt; a while
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;
&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
Testing&lt;/a&gt; spots real
test coverage issues which regular line-based coverage won&amp;rsquo;t
catch. The approach presented in the paper runs mutation testing in
the context of a code review, which narrows the surfaced issues to the
code you&amp;rsquo;re already working on, and keeps them actionable.&lt;/p&gt;
&lt;h2 id=&#34;example&#34;&gt;Example&lt;/h2&gt;
&lt;p&gt;To get an idea how the approach in the paper works in practice: Let&amp;rsquo;s
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
mutation testing enabled, the infrastructure would now catch us and
report something like this (from page 2 in the paper):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;Changing this 1 line to

  if (a != b || b == 1) {

does not cause any test exercising them to fail.

Consider adding test cases that fail when the code is mutated to
ensure those bugs would be caught.

Mutants ran because goranpetrovic is whitelisted.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;how-did-it-figure-that-out&#34;&gt;How did it figure that out?&lt;/h2&gt;
&lt;p&gt;Mutation Testing runs on a proposed change during a code review, so
the problem is defined (a) through a bunch of changes to production
code and (b) implicitly through the tests exercising that code.&lt;/p&gt;
&lt;p&gt;The mutation testing infrastructure now attempts the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Purposefully modify program logic&lt;/strong&gt; in the code under test
(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;
&lt;li&gt;&lt;strong&gt;Check if any of the tests starts failing&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We messed up the code under test, so with good &amp;ldquo;logical coverage&amp;rdquo;, one
of the tests should now have failed.  But if all tests have still
passed, we apparently have changed logic that wasn&amp;rsquo;t properly tested.&lt;/p&gt;
&lt;h2 id=&#34;mutation-testing-is-underrated&#34;&gt;Mutation Testing is underrated&lt;/h2&gt;
&lt;p&gt;Even though it looks like it&amp;rsquo;s originally coming from a more academic
corner, &lt;strong&gt;Mutation Testing works in practice.&lt;/strong&gt; The examples in the
paper are not made up, and they saved me from real bugs.&lt;/p&gt;
&lt;p&gt;I hope that there will be more implementations in the wild at some
point. It&amp;rsquo;s worth the effort.&lt;/p&gt;
&lt;section class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;Google started publishing more material on
internal developer tooling in the recent years. I ♥ it because I
can now point to papers rather than to Google PR when people ask
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;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;The list of implemented mutations is at the top of page
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;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
    </item>
    
    <item>
      <title>Wireguard is in the Linux kernel</title>
      <link>https://blog.gnoack.org/post/wireguard/</link>
      <pubDate>Mon, 09 Dec 2019 22:59:00 +0200</pubDate>
      
      <guid>https://blog.gnoack.org/post/wireguard/</guid>
      <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
kernel&lt;/a&gt;
and &lt;a href=&#34;https://lists.zx2c4.com/pipermail/wireguard/2019-December/004704.html&#34;&gt;will be part of Linux
5.6&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Wireguard was quite a relief for me after wrestling with OpenVPN
before, for multiple reasons. I&amp;rsquo;m a happy user for about a year now,
and I can wholeheartedly recommend it.&lt;/p&gt;
&lt;p&gt;Wireguard is really pushing the state of the art forward for VPNs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;high performance&lt;/strong&gt; (it&amp;rsquo;s part of the kernel)&lt;/li&gt;
&lt;li&gt;very &lt;strong&gt;simple setup&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;no wrestling with OpenSSL or X.509 certificates&lt;/li&gt;
&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;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;excellent apps&lt;/strong&gt; for
&lt;a href=&#34;https://play.google.com/store/apps/details?id=com.wireguard.android&#34;&gt;Android&lt;/a&gt;
and &lt;a href=&#34;https://apps.apple.com/de/app/wireguard/id1441195209&#34;&gt;iOS&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;full config files can be provided as QR codes&lt;/li&gt;
&lt;li&gt;it &lt;strong&gt;does not drain&lt;/strong&gt; your battery (a mostly stateless protocol)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.wireguard.com/install/&#34;&gt;support for many platforms&lt;/a&gt;
apart from Linux through a user space implementation&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;an-example-configuration&#34;&gt;An example configuration&lt;/h2&gt;
&lt;p&gt;To get an idea, this is a &lt;code&gt;/etc/wireguard/wg0.conf&lt;/code&gt; configuration file
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;
&lt;pre&gt;&lt;code class=&#34;language-ini&#34;&gt;[Interface]
PrivateKey = WG8r5DNvD2KlZORhJ2XgzW3lWO8i5GJqZBePt98EgUY=
Address = 192.168.23.10/32
DNS = 192.168.23.1

[Peer]
PublicKey = 6qzH9hJbyPFp+GJJoxsBaPhUEl4mVKTGNP433xLWhBc=
PresharedKey = LiWmdHZN/Jizhv1h0qTGeslci2yZIyrkEDjrx3bUomE=
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = vpn.gnoack.org:9999
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This contains our own device&amp;rsquo;s private key and configured IP in the
VPN, as well as a list of peer hosts with their public keys and the IP
addresses they are making available.&lt;/p&gt;
&lt;p&gt;Note the symmetry: A server-side configuration looks the
same, but with more peer entries.&lt;/p&gt;
&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
appropriate routes.&lt;/p&gt;
&lt;p&gt;For further reference, &lt;a href=&#34;https://www.wireguard.com/quickstart/&#34;&gt;Wireguard&amp;rsquo;s own quickstart
page&lt;/a&gt; has a better introduction
than this one here (with a video).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: I&amp;rsquo;m not affiliated with Wireguard, but I received a
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
once. Congratulations on the big step forward, and thanks for the
great software!&lt;/p&gt;
&lt;section class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;Key management can hardly be simpler than that:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;$ wg genkey &amp;gt; beuys.gnoack.org
$ wg pubkey &amp;lt; beuys.gnoack.org
tw6MlpAFMoQInDC402FndO8Z49/H4cT11BYOHDRkcys=
$ wg genpsk &amp;gt; psk
&lt;/code&gt;&lt;/pre&gt;
&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;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34; role=&#34;doc-endnote&#34;&gt;
&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;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;That was really nice. As everyone knows, stickers beat
Bitcoin and Ethereum hands down as an underground hacker
currency. :) They were quite popular in the sticker exchange where
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;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
    </item>
    
    <item>
      <title>Go: Goroutines and Apis</title>
      <link>https://blog.gnoack.org/post/go-goroutines-and-apis/</link>
      <pubDate>Mon, 18 Nov 2019 21:30:53 +0100</pubDate>
      
      <guid>https://blog.gnoack.org/post/go-goroutines-and-apis/</guid>
      <description>&lt;p&gt;Goroutines are a unusual and powerful programming language feature, so
they are a tempting toy to play with, and they get a bit overused.&lt;/p&gt;
&lt;p&gt;There is some indication that the following Go principle holds true:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Strive to provide synchronous APIs,&lt;br&gt;
let the caller start goroutines.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To put this advice into a more concrete code example:&lt;/p&gt;
&lt;p&gt;Do this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-golang&#34;&gt;func (t *type) Run(ctx context.Context) {
    // Implementation of background task
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-golang&#34;&gt;func (t *type) Start() {
    t.wg.Add(1)
    go func() {
      // Implementation of background task
      t.wg.Done()
    }
}

func (t *type) Cancel() {
    // Somehow cancel the background task
    t.wg.Wait()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Upsides for &lt;code&gt;Run()&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The caller gets to decide how the &amp;ldquo;background&amp;rdquo; code gets run.
&lt;ul&gt;
&lt;li&gt;Spawning Goroutines is easy for the caller too.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;go&lt;/code&gt; statements move towards the application&amp;rsquo;s top-level.
Goroutine coordination becomes simpler to reason about when
goroutines are started in fewer places.&lt;/li&gt;
&lt;li&gt;Callers can also run it without goroutine and just block on the
call, if there is no other work to be done.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Background task cancellation is provided through the context.&lt;/li&gt;
&lt;li&gt;Waiting for the background task has a trivial API (when the
function returns), and can be done with the mechanism the
caller prefers (waitgroups, channels, &amp;hellip;)&lt;/li&gt;
&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
callers can forget to call (leaking resources).&lt;/li&gt;
&lt;/ul&gt;
&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
design&lt;/a&gt; podcast
(starting around minute 47, Mat Ryer&amp;rsquo;s explanation really resonated
with me)&lt;/p&gt;
&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
To Do Things&amp;rdquo; by Peter
Bourgon&lt;/a&gt;
&lt;a href=&#34;https://speakerdeck.com/peterbourgon/ways-to-do-things?slide=14&#34;&gt;(slides)&lt;/a&gt;,
who also appeared on the above &amp;ldquo;Go Time&amp;rdquo; episode. The talk describes
the &lt;code&gt;Run()&lt;/code&gt; style quite clearly and in more detail. Thanks for the
excellent pointer, Jacob!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Go: Error handling</title>
      <link>https://blog.gnoack.org/post/go-errors/</link>
      <pubDate>Fri, 18 Oct 2019 20:00:00 +0200</pubDate>
      
      <guid>https://blog.gnoack.org/post/go-errors/</guid>
      <description>&lt;figure&gt;&lt;img src=&#34;https://blog.gnoack.org/images/rakegopher.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;I love Go for many reasons, but this part is still itching me: I
postulate that this Go idiom is a burden on our mental capacity:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-golang&#34;&gt;if err != nil {
        return nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.gnoack.org/post/error_handling&#34;&gt;Error handling&lt;/a&gt; is at a tension between two
different developer needs.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;On the one hand, error handling is very annoying and distracting
when working on a constructively formulated use case.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On the other hand, not dealing with it correctly means that the
program blows up in unknown ways when errors happen: data may be lost,
I/O may be half done, features may stop working without the developers
noticing.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Go&amp;rsquo;s explicitness about error handling makes sure that errors are not
falling through the cracks as easily as they might do in other
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
developers love Go&amp;rsquo;s explicitness, it is rather verbose for error
handling, which has drawbacks:&lt;/p&gt;
&lt;p&gt;(1) &lt;strong&gt;Humans are pattern matching machines&lt;/strong&gt;. Whenever we see text
whose shape resembles the error checking idiom, we have trained
ourselves to quickly look away, at the more important code next to it.
But bugs can hide even in repetitive parts of the code. If we&amp;rsquo;re not
looking at the idiom anyway, the &lt;code&gt;try()&lt;/code&gt; proposal might be the better
option, as it de-duplicates the check.&lt;/p&gt;
&lt;p&gt;(2) &lt;strong&gt;The error handling pattern takes much visual space&lt;/strong&gt;. The idiom
is necessarily interleaved with the code on the happy path. In many
cases, the flow of reading a longer function is interrupted multiple
times with the same 3-line code snippet.&lt;/p&gt;
&lt;h2 id=&#34;two-different-hats&#34;&gt;Two different hats&lt;/h2&gt;
&lt;p&gt;I believe that reasoning about constructive code and reasoning about
error handling code are &lt;em&gt;two separate states of mind&lt;/em&gt;, and switching
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;
&lt;p&gt;A consequence of this is: It might be more productive to spend less
time on errors during an initial implementation, and to then address
the error handling aspect in a separate pass over the code. It
would be better if we could have two views of the code for these
different modes of operation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;For the feature-focused mode, we need a view of the code where the
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
order to make the constructive code more prominent.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For the error-focused mode, an error-only view is not really
possible because errors happen only as a result of constructive
operations, but in many editors, an interactive search for the
keywords &lt;code&gt;return&lt;/code&gt; and &lt;code&gt;try&lt;/code&gt;(?) will highlight the possible exit points
quickly.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&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
&lt;code&gt;try()&lt;/code&gt; proposal&lt;/a&gt;. I&amp;rsquo;m
still sad it didn&amp;rsquo;t go forward, but I&amp;rsquo;m glad the Go team is so careful
about it.&lt;/p&gt;
&lt;p&gt;Just because we have all already invested so much time into accepting
this verbose way of error handling, that doesn&amp;rsquo;t mean it&amp;rsquo;s a good
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;
&lt;section class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34; role=&#34;doc-endnote&#34;&gt;
&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;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34; role=&#34;doc-endnote&#34;&gt;
&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;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34; role=&#34;doc-endnote&#34;&gt;
&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;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34; role=&#34;doc-endnote&#34;&gt;
&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;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
    </item>
    
    <item>
      <title>Dot Space Space</title>
      <link>https://blog.gnoack.org/post/dot-space-space/</link>
      <pubDate>Fri, 30 Aug 2019 09:17:30 +0200</pubDate>
      
      <guid>https://blog.gnoack.org/post/dot-space-space/</guid>
      <description>&lt;p&gt;I have a confession to make. I used to put two spaces after each
sentence, as it used to be done by typewriter typists before computers
[citation needed].&lt;/p&gt;
&lt;p&gt;The moment when I started to form this habit was around 2010. I was
young and easy to impress, and I was picking up more advanced Emacs
use working on the TeX source for my diploma thesis. While editing
these large chunks of free-form text was when I discovered the
&lt;code&gt;fill-paragraph&lt;/code&gt; function, otherwise known as &lt;code&gt;M-q&lt;/code&gt;, for automatically
breaking text at the correct column width. This is very useful for
editing text files, so it quickly became a habit to press &lt;code&gt;M-q&lt;/code&gt; often.
I&amp;rsquo;m still using it right now, in fact.&lt;/p&gt;
&lt;p&gt;Now after a while of using this feature, I started to observe that
this didn&amp;rsquo;t work exactly how I thought. Readjusting text where one
line ends with a full stop, it would surprisingly add two spaces in
the middle after breaking.&lt;/p&gt;
&lt;p&gt;This text:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;Hello world.
This is a text.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Would turn into that text after a press of &lt;code&gt;M-q&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;Hello world.  This is a text.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then somewhere in Emacs documentation, I found key bindings jump back
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
double-spaces to tell apart sentence ends from abbreviations (e.g. as
in Dr. Seuss).&lt;/p&gt;
&lt;p&gt;I did not end up picking up these shortcuts, but it was enough for me
to rationalize the double spaces. In reality of course, I only started
with that habit so that &lt;code&gt;M-q&lt;/code&gt; would not break the otherwise consistent
spacing style accidentally.&lt;/p&gt;
&lt;p&gt;I used this for about 10 years now, and of course it didn&amp;rsquo;t elude me
that I was the only one doing that, but it&amp;rsquo;s hard to put down old
habits.&lt;/p&gt;
&lt;p&gt;Recently, I found what I think is the remedy - &lt;code&gt;M-q&lt;/code&gt; is actually
configurable in Emacs, and the old habit of pressing &lt;code&gt;M-q&lt;/code&gt; will now
just fix my sentences to single-spaces again going forward.&lt;/p&gt;
&lt;p&gt;This is what is needed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-elisp&#34;&gt;(setq sentence-end-double-space nil)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What do we learn from this story? I&amp;rsquo;m not sure. Maybe that old habits
are hard to shake. Some quirks creep in without you noticing and a
tiny change might fix them.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;M-q&lt;/code&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Notes on Plan9&#39;s 9P protocol</title>
      <link>https://blog.gnoack.org/post/9pnotes/</link>
      <pubDate>Fri, 22 Mar 2019 12:26:34 +0100</pubDate>
      
      <guid>https://blog.gnoack.org/post/9pnotes/</guid>
      <description>&lt;p&gt;The 9P protocol is the protocol for network file systems used in
Plan9.  Plan9 is not a widely used operating system, but it&amp;rsquo;s widely
considered more true to the Unix spirit than Unix is, coming from some
of the same people who made Unix as well.&lt;/p&gt;
&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;
&lt;p&gt;To get a rough idea of the 9P protocol, consider a system where all
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;,
&amp;hellip;)  are lifted to be remote procedure calls.  These can be sent over
the network, making file systems in Plan9 network transparent.&lt;/p&gt;
&lt;p&gt;9P&amp;rsquo;s RPCs are documented in Plan9&amp;rsquo;s man page section 5
(&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;
&lt;ul&gt;
&lt;li&gt;Session control
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;version&lt;/code&gt; to negotiate the protocol version.&lt;/li&gt;
&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;
&lt;li&gt;&lt;code&gt;flush&lt;/code&gt; to cancel ongoing requests.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Basic file operations:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;open&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;clunk&lt;/code&gt; (equivalent to &lt;code&gt;close&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;read&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;write&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Working with directories
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;walk&lt;/code&gt; to descend a directory hierarchy.&lt;/li&gt;
&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
(e.g. to rename files).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;remove&lt;/code&gt; for removing file entries.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition, there is an &lt;code&gt;error&lt;/code&gt; response which may be returned as
response to any of these requests.&lt;/p&gt;
&lt;p&gt;The handle to a file is called &amp;ldquo;file ID&amp;rdquo; (fid) in Plan9 lingo.  This
can be thought of as a file descriptor.&lt;/p&gt;
&lt;p&gt;The 9P protocol does away with a bunch of complexities that Unix, and
particularly Linux has started to have.  Some of the non-supported
features are:&lt;/p&gt;
&lt;ul&gt;
&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.
Presumably it can be emulated within limits if needed.&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;ioctl&lt;/code&gt;.  Control-style operations are often done through reads and writes
to special purpose files.  There are often textual command languages.&lt;/li&gt;
&lt;li&gt;There is a more blurry line between different file types as in Unix,
where you can distinguish named pipes, device files and regular files.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;playing-with-plan9port&#34;&gt;Playing with Plan9port&lt;/h2&gt;
&lt;p&gt;An easy way to play with 9P is to install Plan9port, a Linux userspace
port of Plan9&amp;rsquo;s core tools and wiring, which comes as installable
package with many Linux distributions.&lt;/p&gt;
&lt;p&gt;Plan9port includes the Plan9 compiler, the acme text editor and other
things, including source code.  Many of these tools are exposing 9P
file systems over Unix sockets in the &lt;code&gt;/tmp/ns.$USER.$DISPLAY&lt;/code&gt;
directory.  You can get your exact location by running the &lt;code&gt;namespace&lt;/code&gt;
tool:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;$ namespace
/tmp/ns.me:0
$
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For example, you might want to start up the &lt;code&gt;factotum&lt;/code&gt; authentication
service and have a peek at the created file system.  Plan9port&amp;rsquo;s &lt;code&gt;9p&lt;/code&gt;
tool lets you do simple accesses from the command line:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;$ /usr/lib/plan9/bin/factotum
$ ls $(namespace)
factotum
$ 9p ls factotum
confirm
conv
ctl
log
needkey
proto
rpc
$
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are also public 9P services, such as the Plan9 &amp;ldquo;sources&amp;rdquo;
repository.  After the Bell Labs server went down, these continue to
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
a wrapper for quickly mounting this remote service, but needs a little
modification for convenience:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;$ cat $PLAN9/bin/9fs \
  | sed -e &#39;s/sources.cs.bell-labs.com/sources.9p.io/&#39; &amp;gt; ~/9fs
$ chmod +x ~/9fs
$ ~/9fs sources
$ 9p ls -l sources
d-rwxrwxr-x M 0 9grid  9grid       0 Jul 15  2018 9grid
--rw-rw-r-- M 0 bootes sys         0 Jun 24  2013 _sources
d-rwxrwxr-x M 0 adm    sys         0 Jul 15  2018 adm
d-rwxrwxr-x M 0 sys    sys         0 Oct 28 19:18 contrib
d-rwxrwxr-x M 0 bootes sys         0 Jul 15  2018 dist
d-rwxrwxr-x M 0 sys    sys         0 Jul 15  2018 extra
--rw-rw-r-- M 0 bootes adm   9142602 Jan 23  2015 lsr
d-rwxrwxr-x M 0 geoff  nix         0 Jul 15  2018 nix
d-rwxrwxrwx M 0 glenda sys         0 Jul 15  2018 patch
d-rwxrwxr-x M 0 sys    sys         0 Jul 15  2018 plan9
d-rwxrwxr-x M 0 sys    sys         0 Jul 15  2018 wiki
d-rwxrwxr-x M 0 xen    xen         0 Jul 15  2018 xen
$
&lt;/code&gt;&lt;/pre&gt;
&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
file system which comes with Plan9port:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;$ 9pfuse unix\!/tmp/ns.$USER.:0/sources /tmp/sources
$ ls /tmp/sources
9grid  contrib  extra  nix    plan9     wiki
adm    dist     lsr    patch  _sources  xen
$
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;looking-under-the-hood&#34;&gt;Looking under the hood&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s first read a small file from the Plan9 sources repo:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;$ 9p read sources/plan9/NOTICE
Copyright © 2002 Lucent Technologies Inc.
All Rights Reserved
$
&lt;/code&gt;&lt;/pre&gt;
&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
to print all requests and responses.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;$ 9p -D read sources/plan9/NOTICE
&amp;lt;- Tversion tag 0 msize 8192 version &#39;9P2000&#39;
-&amp;gt; Rversion tag 65535 msize 8192 version &#39;9P2000&#39;
&amp;lt;- Tauth tag 0 afid 0 uname me aname &amp;lt;nil&amp;gt;
-&amp;gt; Rerror tag 0 ename authentication rejected
&amp;lt;- Tattach tag 0 fid 0 afid -1 uname me aname
-&amp;gt; Rattach tag 0 qid (0000000000000002 0 d)
&amp;lt;- Twalk tag 0 fid 0 newfid 1 nwname 2 0:plan9 1:NOTICE
-&amp;gt; Rwalk tag 0 nwqid 2 0:(0000000000081aa0 78 d) 1:(0000000000081d2d 1 )
&amp;lt;- Topen tag 0 fid 1 mode 0
-&amp;gt; Ropen tag 0 qid (0000000000081d2d 1 ) iounit 8168
&amp;lt;- Tread tag 0 fid 1 offset 0 count 4096
-&amp;gt; Rread tag 0 count 63 &#39;436f7079 72696768 7420c2a9 20323030 32204c75 ...&#39;
Copyright © 2002 Lucent Technologies Inc.
All Rights Reserved
&amp;lt;- Tread tag 0 fid 1 offset 63 count 4096
-&amp;gt; Rread tag 0 count 0 &#39;&#39;
&amp;lt;- Tclunk tag 0 fid 1
-&amp;gt; Rclunk tag 0
$
&lt;/code&gt;&lt;/pre&gt;
&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
to the backend service.&lt;/p&gt;
&lt;p&gt;The steps are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Version negotiation: Both sides confirm the 9P variant they want
to speak.&lt;/li&gt;
&lt;li&gt;Authentication: The &lt;code&gt;auth&lt;/code&gt; call is normally supposed to return an
open file ID, over which to speak an authentication protocol. In
this case, the service permits unauthenticated read accesses, so
this is returning an error.&lt;/li&gt;
&lt;li&gt;Attaching to the service, retrieving the desired root directory,
in this case it&amp;rsquo;s just the root.
(Note, the client picks which FID it would like to use for
identifying files.)&lt;/li&gt;
&lt;li&gt;Walking down to the desired file from the root FID 0, yielding
the new FID 1.&lt;/li&gt;
&lt;li&gt;Opening the FID for reading.&lt;/li&gt;
&lt;li&gt;Calling &lt;code&gt;read&lt;/code&gt; until nothing is returned any more.&lt;/li&gt;
&lt;li&gt;Closing the FID with &lt;code&gt;clunk&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;some-resources&#34;&gt;Some resources&lt;/h2&gt;
&lt;ul&gt;
&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;
&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;
&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;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>How to review code</title>
      <link>https://blog.gnoack.org/post/code_reviews/</link>
      <pubDate>Thu, 14 Mar 2019 13:00:06 +0200</pubDate>
      
      <guid>https://blog.gnoack.org/post/code_reviews/</guid>
      <description>&lt;figure&gt;&lt;img src=&#34;images/2011.09.18_code_reviews.png&#34;
         alt=&#34;A code review that doesn&amp;amp;rsquo;t go right. (image by Manu Cornet, CC BY-NC-ND 3.0)&#34;/&gt;&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;
&lt;/figure&gt;

&lt;p&gt;I&amp;rsquo;ve reviewed over 3000 code changes so far in my career, and gone
through about same amount of reviews as change author.  When reviewing
code, here is the golden rule I follow:&lt;/p&gt;
&lt;blockquote class=&#34;info&#34;&gt;Any code change that&amp;rsquo;s a strict improvement should be approved.&lt;/blockquote&gt;

&lt;p&gt;Most incoming code reviews are both improvements in some aspects and
make things worse in other aspects.&lt;/p&gt;
&lt;h2 id=&#34;understand-the-change&#34;&gt;Understand the change&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s tempting to glance over a change and only comment on small
technical details or style issues, but this will eventually lead to
worse code.  In order to give meaningful feedback, understand the
change to the extent where you could have authored it yourself.&lt;/p&gt;
&lt;h2 id=&#34;blocking-issues-to-look-out-for&#34;&gt;Blocking issues to look out for&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;New code is unclear.&lt;/strong&gt; Ask: &amp;ldquo;I do not understand this&amp;rdquo;.  Insist
that it&amp;rsquo;s clarified in the final submitted code rather than in a
review comment.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;New code is missing tests.&lt;/strong&gt; Insist.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;New code does not fit into surrounding code&lt;/strong&gt; in terms of style
or common libraries used.  Insist.  Link to a canonical style guide
whenever you can.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pre-existing tests were changed willy-nilly until they run
green.&lt;/strong&gt; This often takes the form of only a few lines added to
every existing test case.  These drive-by fixes accumulate easily
over the course of some changes, until the core idea behind the
test cases is obstructed.  Insist on refactoring the tests.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;New code introduces duplication&lt;/strong&gt; with existing code.  Ask to
deduplicate.  (This is particularly often seen in tests.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The change is increasing code complexity.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Is there a better solution you can suggest?&lt;/li&gt;
&lt;li&gt;Does the change&amp;rsquo;s benefit outweigh the additional complexity?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The change introduces dependencies in places where they don&amp;rsquo;t
belong.&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;non-blocking-issues-to-look-out-for&#34;&gt;Non-blocking issues to look out for&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s fine to ask for additional changes that are not strictly
required, but always make it clear that they are optional.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;I would have done it differently.&amp;quot;&lt;/strong&gt; is a gut reaction almost
all reviewers have sometimes.  But it&amp;rsquo;s a shortcut heuristic the
mind takes which usually has a more solid technical background.
&lt;blockquote class=&#34;info&#34;&gt;Learn the specific technical background to your gut
reactions, so you can give concrete advice.&lt;/blockquote&gt;
 If
you can&amp;rsquo;t find a specific technical problem, consider asking why it
was done in that particular way.  There are often be good reasons
which only need to be clarified a bit in the code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pre-existing issues.&lt;/strong&gt; Point out if pre-existing issues can be
fixed in the same change, but explicitly mark it as optional.  Even
when not done immediately, this discussion helps to form a common
understanding which pre-existing patterns in the code should be
avoided and kept.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;taking-technical-debt-a-game-of-trust&#34;&gt;Taking technical debt: A game of trust&lt;/h2&gt;
&lt;p&gt;Sometimes you will want to approve newly introduced issues and
postpone their fixes until later
(&lt;a href=&#34;https://en.m.wikipedia.org/wiki/Technical_debt&#34;&gt;Technical debt&lt;/a&gt;).
Insist that the author will fix these issues after the submission.&lt;/p&gt;
&lt;p&gt;In these cases, code reviews are a game of trust.  A strategy that
works for me is: Assume the best from people you don&amp;rsquo;t know yet, but
don&amp;rsquo;t let them pass a second time if they didn&amp;rsquo;t pay off the technical
debt.&lt;/p&gt;
&lt;p&gt;Good ways to track technical debt issues are (1) a good memory for
names, (2) a shared bug tracker and (3) &lt;code&gt;TODO&lt;/code&gt; markers in the code
(for smaller things).&lt;/p&gt;
&lt;h2 id=&#34;behaviors-to-avoid-as-a-reviewer&#34;&gt;Behaviors to avoid as a reviewer&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&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,
explain immediately why you can&amp;rsquo;t do it (yet) and redirect to
someone better suited if possible.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Never insist that reviewees fix pre-existing issues.&lt;/strong&gt; Being code
reviewer is a position of power, but it&amp;rsquo;s not a free pass to
blackmail others into doing your work.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Don&amp;rsquo;t block legitimate changes for corporate politics reasons.&lt;/strong&gt;
This should go without saying.  Do not use code reviews to unjustly
influence project priorities.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;parting-words&#34;&gt;Parting words&lt;/h2&gt;
&lt;p&gt;I hope this collection of code reviewing tips will help someone to
have more constructive code reviews. Remember:&lt;/p&gt;
&lt;blockquote class=&#34;info&#34;&gt;The reviewer&amp;rsquo;s job is not to stand in the way, but to enable
the code submitter to do their best work.&lt;/blockquote&gt;

&lt;p&gt;Feedback is always appreciated. :)&lt;/p&gt;
&lt;blockquote class=&#34;info&#34;&gt;Update 2019-09-05: My colleague &lt;a href=&#34;https://twitter.com/mkanat&#34;&gt;Max
Kanat-Alexander&lt;/a&gt; has compiled and open
sourced Google&amp;rsquo;s guidelines for code reviews at
&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
compiled from the input of many engineers and has a lot of good
advice. I can wholeheartedly endorse this.&lt;/blockquote&gt;

</description>
    </item>
    
    <item>
      <title>Procedurally generated trees</title>
      <link>https://blog.gnoack.org/post/trees/</link>
      <pubDate>Wed, 23 Jan 2019 11:35:00 +0200</pubDate>
      
      <guid>https://blog.gnoack.org/post/trees/</guid>
      <description>&lt;figure class=&#34;nomargin&#34;&gt;

&lt;script type=&#34;text/paperscript&#34; canvas=&#34;canvas0&#34;&gt;

var x = new Point(1, 0);
var y = new Point(0, 1);

function config(treeColor, leafColor) {
    return {
        treeColor: treeColor,
        leafColor: leafColor
    }
}

function leaf(pt, angle, length, cfg) {
  var r = length / 3;
  var tip = pt - y*length;
  var mid = pt - y*(length/2);
  var l = new Path([
      new Segment(pt, - x*r, + x*r),
      new Segment(tip, + x*(r/2), - x*(r/2)),
      new Segment(pt, - x*r, + x*r)
  ]);
  l.rotate(angle, pt);
  l.style = { fillColor: cfg.leafColor, closed: true };
}

function branchpart(pt, angle, width, length, cfg) {
    var wh = width/2;
    var rect = Path.Rectangle(
          pt - x*wh + y*wh,
          pt + x*wh - y*(length+wh));
    rect.style = { fillColor: cfg.treeColor };
    rect.rotate(angle, pt);

    var nextroot = (pt - y*length).rotate(angle, pt);
    return {
        rect: rect,
        next: nextroot,
    }
}

function branch(pt, angle, width, length, cfg) {
  var b = branchpart(pt, angle, width, length, cfg);

  if (width &gt; 3) {
      // Recurse
      var n = b.next;
      var area = width*width;
      var ffrac = Math.random(); // first branch fraction of area
      var sfrac = 1-ffrac;  // same for second branch


      if (ffrac &gt; 0.05) {
        var fangle = angle + (1-ffrac)*45;
        branch(n, fangle, Math.sqrt(area*ffrac), length*0.92, cfg);
      }
      if (sfrac &gt; 0.05) {
        var sangle = angle - (1-sfrac)*45;
        branch(n, sangle, Math.sqrt(area*sfrac), length*0.92, cfg);
      }
  } else {
    leaf(b.next, angle, 20, cfg);
  }
}

function tree(pt, cfg) {
  branch(pt, 0, 40, 35, cfg);
}

function threeTreeHorizontalScene() {
    var fullwidth = paper.view.size.width;
    var height = paper.view.size.height;
    var border = Math.round(fullwidth/12) + 50;
    var frame = Path.Rectangle(new Point(border, height-322), new Point(fullwidth-border, height-2));
    frame.style = {
        fillColor: &#39;white&#39;,
        strokeColor: &#39;black&#39;,
        strokeWidth: 2
    }

    var innerwidth = fullwidth - 2*border;
    if (innerwidth &gt; 320) {
        tree(new Point(border + Math.round(innerwidth*(1/3)), height-23), config(&#34;black&#34;, &#34;Orange&#34;));
        tree(new Point(border + Math.round(innerwidth*(2/3)), height-23), config(&#34;black&#34;, &#34;#ec5800&#34;));
    } else {
        tree(new Point(border + Math.round(innerwidth*(1/2)), height-23), config(&#34;black&#34;, &#34;#03992c&#34;));
    }
}

threeTreeHorizontalScene();

&lt;/script&gt;
&lt;canvas data-paper-resize=&#34;true&#34; id=&#34;canvas0&#34; style=&#34;width:120%; margin-left: -10%; margin-right: -10%; height: 400px;&#34;&gt;&lt;/canvas&gt;

&lt;figcaption&gt;&lt;p&gt;These trees are procedurally regenerated on every page load.&lt;/p&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&#34;basic-algorithm&#34;&gt;Basic algorithm&lt;/h2&gt;
&lt;p&gt;At the heart of this algorithm, there is a recursive function which
draws a tree branch (as a rotated black rectangle) and its
sub-branches.  The function calls itself recursively for the two
sub-branches, using smaller branch sizes.  When the width is finally
too small to continue for the branch we&amp;rsquo;re looking at, we draw a leaf
and stop there.&lt;/p&gt;
&lt;p&gt;To randomize the tree shape, we&amp;rsquo;re picking two weights from 0 to 1 for
the two branches, which are adding up to 1.  The weights are used to
determine the sub-branch sizes and angles.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The two sub-branches should together have the same surface area as
the parent when you saw through them. The surface area is split
according to weight.&lt;/li&gt;
&lt;li&gt;Big sub-branches (with big weight) grow straight ahead, while small
ones grow more to the side, up to 45°.&lt;/li&gt;
&lt;li&gt;Very small sub-branches with too small weights are cut off and not
drawn anymore.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;background&#34;&gt;Background&lt;/h2&gt;
&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;,
which I discovered through
&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;
</description>
    </item>
    
    <item>
      <title>Internet of Things: Wifi Radio</title>
      <link>https://blog.gnoack.org/post/wifi_radio/</link>
      <pubDate>Wed, 09 Jan 2019 12:05:01 +0100</pubDate>
      
      <guid>https://blog.gnoack.org/post/wifi_radio/</guid>
      <description>&lt;blockquote class=&#34;info&#34;&gt;Update: This setup stopped working after a few firmware
updates; there were apparently some software updates after the
&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;.
Maybe they also read my bug report about the broken encoding and found
my blog post. I didn&amp;rsquo;t investigate much; superficially it looked like
the radio is just ignoring the returned IP address if it&amp;rsquo;s a local
one.&lt;/blockquote&gt;

&lt;p&gt;Have you ever wondered what your Internet-connected devices are doing
behind your back?&lt;/p&gt;
&lt;p&gt;My internet radio had some problems with displaying special characters
in the list of radio stations. When I
&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;,
I found that the protocol for connecting back was unencrypted, so I
made it talk through a proxy which modifies the responses on the fly
to fix up wrong character encoding in the server responses.&lt;/p&gt;
&lt;p&gt;Basic setup:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The router giving out DHCP leases makes clients talk to its own local DNS service.&lt;/li&gt;
&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;
&lt;li&gt;The Raspberry Pi acts as a reverse HTTP proxy for the actual domain and modifies
requests along the way.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img src=&#34;images/diagram600.png&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Reverse proxies are simple to write in Go: use
&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;
and then set the &lt;code&gt;ReverseProxy.ModifyResponse&lt;/code&gt; property on the
returned object to an appropriate modification function such as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;func Modify(resp *http.Response) error {
        b, err := ioutil.ReadAll(resp.Body)
        resp.Body.Close()
        if err != nil {
                return err
        }
        b = ModifyBody(b)  // Actual replacements done here.
        resp.Body = ioutil.NopCloser(bytes.NewReader(b))
        resp.ContentLength = int64(len(b))
        resp.Header.Set(&amp;quot;Content-Length&amp;quot;, strconv.Itoa(len(b)))
        return nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my implementation, I&amp;rsquo;m replacing some wrongly encoded characters
with correct ones in the server response, and for demo purposes and
some silly entertainment, I&amp;rsquo;m changing the German word for Switzerland
to &amp;ldquo;Swizzle&amp;rdquo;:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;images/radio600.png&#34;/&gt;
&lt;/figure&gt;

</description>
    </item>
    
    <item>
      <title>Shared base fixture</title>
      <link>https://blog.gnoack.org/post/base_fixture/</link>
      <pubDate>Tue, 06 Nov 2018 07:44:44 +0100</pubDate>
      
      <guid>https://blog.gnoack.org/post/base_fixture/</guid>
      <description>&lt;figure&gt;
  &lt;div id=&#39;pikchr-0&#39; class=&#39;pikchr&#39;&gt;
&lt;div class=&#39;pikchr-svg&#39; style=&#39;max-width:537px&#39;&gt;
&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#34;0 0 537.726 286.526&#34;&gt;
&lt;polygon points=&#34;74,63 62,67 62,58&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M2,63L68,63&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;38&#34; y=&#34;51&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;make&lt;/text&gt;
&lt;path d=&#34;M74,91L159,91L159,34L74,34Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;116&#34; y=&#34;53&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;base&lt;/text&gt;
&lt;text x=&#34;116&#34; y=&#34;73&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;case&lt;/text&gt;
&lt;polygon points=&#34;385,63 374,67 374,58&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M159,63L380,63&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M385,91L471,91L471,34L385,34Z&#34;  style=&#34;fill:rgb(240,255,240);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;428&#34; y=&#34;63&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;result&lt;/text&gt;
&lt;path d=&#34;M159,176L244,176L244,119L159,119Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;201&#34; y=&#34;138&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;derived&lt;/text&gt;
&lt;text x=&#34;201&#34; y=&#34;158&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;case 1&lt;/text&gt;
&lt;path d=&#34;M159,261L244,261L244,204L159,204Z&#34;  style=&#34;fill:rgb(255,228,196);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;201&#34; y=&#34;223&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;derived&lt;/text&gt;
&lt;text x=&#34;201&#34; y=&#34;243&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;case 2&lt;/text&gt;
&lt;path d=&#34;M385,176L471,176L471,119L385,119Z&#34;  style=&#34;fill:rgb(240,255,240);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;428&#34; y=&#34;148&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;result&lt;/text&gt;
&lt;path d=&#34;M385,261L471,261L471,204L385,204Z&#34;  style=&#34;fill:rgb(240,255,240);stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;text x=&#34;428&#34; y=&#34;233&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;result&lt;/text&gt;
&lt;polygon points=&#34;385,148 374,152 374,143&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M244,148L380,148&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;polygon points=&#34;385,233 374,237 374,229&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M244,233L380,233&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M116,91L116,233&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;polygon points=&#34;159,233 147,237 147,229&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M116,233L153,233&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;polygon points=&#34;159,148 147,152 147,143&#34; style=&#34;fill:rgb(0,0,0)&#34;/&gt;
&lt;path d=&#34;M116,148L153,148&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);&#34; /&gt;
&lt;path d=&#34;M266,12L266,284&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:7.2,7.2;&#34; /&gt;
&lt;path d=&#34;M363,12L363,284&#34;  style=&#34;fill:none;stroke-width:2.16;stroke:rgb(0,0,0);stroke-dasharray:7.2,7.2;&#34; /&gt;
&lt;text x=&#34;507&#34; y=&#34;43&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;expect&lt;/text&gt;
&lt;text x=&#34;507&#34; y=&#34;63&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;happy&lt;/text&gt;
&lt;text x=&#34;507&#34; y=&#34;83&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;case&lt;/text&gt;
&lt;text x=&#34;507&#34; y=&#34;128&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;expect&lt;/text&gt;
&lt;text x=&#34;507&#34; y=&#34;148&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;corner&lt;/text&gt;
&lt;text x=&#34;507&#34; y=&#34;168&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;case 1&lt;/text&gt;
&lt;text x=&#34;507&#34; y=&#34;213&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;expect&lt;/text&gt;
&lt;text x=&#34;507&#34; y=&#34;233&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;corner&lt;/text&gt;
&lt;text x=&#34;507&#34; y=&#34;253&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;case 2&lt;/text&gt;
&lt;text x=&#34;201&#34; y=&#34;12&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;set up&lt;/text&gt;
&lt;text x=&#34;428&#34; y=&#34;12&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;verify result&lt;/text&gt;
&lt;text x=&#34;315&#34; y=&#34;12&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; dominant-baseline=&#34;central&#34;&gt;exercise&lt;/text&gt;
&lt;text x=&#34;116&#34; y=&#34;152&#34; text-anchor=&#34;middle&#34; fill=&#34;rgb(0,0,0)&#34; transform=&#34;rotate(-90 116,162)&#34; dominant-baseline=&#34;central&#34;&gt;modify&lt;/text&gt;
&lt;/svg&gt;
&lt;/div&gt;
&lt;/div&gt;

  &lt;figcaption&gt;&lt;p&gt;A diagram of how different tests share common test setup with a shared base fixture&lt;/p&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;Q&lt;/strong&gt;: How do you know you can trust your test set-up?&lt;br&gt;
&lt;strong&gt;A&lt;/strong&gt;: You reuse a well-known test set up in every test.&lt;/p&gt;
&lt;h2 id=&#34;example-code&#34;&gt;Example code&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def test_simple():
  req = set_up_working_request()
  resp = invoke(req)
  assert resp.status == OK

def test_invalid_page_size():
  req = set_up_working_request()
  req.page_size = -5
  resp = invoke(req)
  assert resp.status == INVALID_ARGUMENT
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the test,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We call &lt;code&gt;set_up_working_request()&lt;/code&gt; and we know this results in
&amp;ldquo;working&amp;rdquo; behavior.  Then we purposefully inject a defective
negative page size into the working request.&lt;/li&gt;
&lt;li&gt;We exercise the system under test in the same way.&lt;/li&gt;
&lt;li&gt;We expect a different result.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because the only difference in set up between &lt;code&gt;test_simple&lt;/code&gt; and
&lt;code&gt;test_invalid_page_size&lt;/code&gt; was in the differing page size, we can easily
reason that the different response status is resulting from just that.&lt;/p&gt;
&lt;h2 id=&#34;related-techniques&#34;&gt;Related techniques&lt;/h2&gt;
&lt;p&gt;This works well together with these techniques:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Structure your test methods with &lt;strong&gt;separate set up, exercise and
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;
&lt;li&gt;Use &lt;strong&gt;explicit helper functions for set up&lt;/strong&gt; and possibly name them
according to expected behavior such as &amp;ldquo;working&amp;rdquo; in the example
above.&lt;/li&gt;
&lt;li&gt;Keep the shared &lt;strong&gt;set up code in test methods as short as
possible&lt;/strong&gt;, so that it&amp;rsquo;s easy to spot the equal parts.&lt;/li&gt;
&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
as a base for multiple derived scenarios.&lt;/li&gt;
&lt;/ul&gt;
&lt;section class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34; role=&#34;doc-endnote&#34;&gt;
&lt;p&gt;This is called the &amp;ldquo;Four-Phase test&amp;rdquo; in the xUnit
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;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
    </item>
    
    <item>
      <title>Günther Noack</title>
      <link>https://blog.gnoack.org/about/</link>
      <pubDate>Fri, 21 Sep 2018 22:13:35 +0200</pubDate>
      
      <guid>https://blog.gnoack.org/about/</guid>
      <description>&lt;p&gt;If you&amp;rsquo;re reading this you found my weblog,
where I post interesting things about computers and software.&lt;/p&gt;
&lt;p&gt;I started programming for fun at an early age in 1993 and for money
in 2003. These days, I work as a Senior Software Engineer at Google in
Zurich. I&amp;rsquo;m a Linux user since 1999.&lt;/p&gt;
&lt;p&gt;My long term interests include software security, software design,
programming languages and operating systems.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m blogging since 2005.  My old weblog is available
&lt;a href=&#34;https://www.unix-ag.uni-kl.de/~guenther/archive.html&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thoughts expressed on this website are my own and do not
represent my employer.&lt;/p&gt;
&lt;h2 id=&#34;contact&#34;&gt;Contact&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;E-Mail: &lt;a href=&#34;mailto:gnoack3000@gmail.com&#34;&gt;gnoack3000@gmail.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Github: &lt;a href=&#34;https://github.com/gnoack&#34;&gt;https://github.com/gnoack&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I am not an avid user of social media.
The best way to reach me is e-mail.&lt;/p&gt;
&lt;h2 id=&#34;subscribe&#34;&gt;Subscribe&lt;/h2&gt;
&lt;p&gt;You can subscribe to this weblog with a suitable feed reader software
through &lt;a href=&#34;https://blog.gnoack.org/post/index.xml&#34;&gt;its RSS feed&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also occasionally post on &lt;a href=&#34;https://lore.kernel.org/all/?q=a:gnoack3000@gmail.com+OR+a:gnoack@google.com&#34;&gt;the Linux kernel mailing lists&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;technicalities&#34;&gt;Technicalities&lt;/h2&gt;
&lt;p&gt;I made this weblog with Hugo, and a heavily hacked
&lt;a href=&#34;https://github.com/EmielH/tale-hugo/&#34;&gt;Tale&lt;/a&gt; theme.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>No error left behind</title>
      <link>https://blog.gnoack.org/post/error_handling/</link>
      <pubDate>Mon, 03 Sep 2018 22:36:41 +0200</pubDate>
      
      <guid>https://blog.gnoack.org/post/error_handling/</guid>
      <description>&lt;figure class=&#34;nomargin&#34;&gt;&lt;img src=&#34;https://blog.gnoack.org/images/reliability.svg&#34;
         alt=&#34;Cartoon in the style of webcomicname.com - first panel: Stakeholder: &amp;#39;Make it do X&amp;#39; Developer: &amp;#39;OK&amp;#39;; second panel: developer works on machine, thinks: &amp;#39;X X X X X&amp;#39;; third panel: user uses the machine saying &amp;#39;Y&amp;#39;. Machine: explodes. Developer: &amp;#39;oh no&amp;#39;&#34;/&gt;
&lt;/figure&gt;

&lt;p&gt;Which design guidelines should software follow in order to run
reliably?  Which guidelines do you use in your day-to-day work?&lt;/p&gt;
&lt;p&gt;Error handling is a significant complexity in real-world projects, but
programming textbooks are often giving very little advice on how to
think about it at the higher level.  This article tries to fill that
gap:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We will define what an error is.&lt;/li&gt;
&lt;li&gt;We will find out that each error has a human stakeholder.&lt;/li&gt;
&lt;li&gt;We will discuss technical mechanisms to bring errors to human attention.&lt;/li&gt;
&lt;li&gt;The final section contains various examples of how to apply this.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To handle the error cases in your software, you should ask yourself
who is the human stakeholder who would be able to address it, and then
find a suitable mechanism to escalate the error in the direction of
that stakeholder.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve cross-checked this approach with multiple people from various
software backgrounds, but I&amp;rsquo;m still happy to receive your feedback.&lt;/p&gt;
&lt;h1 id=&#34;what-is-an-error&#34;&gt;What is an error?&lt;/h1&gt;
&lt;blockquote class=&#34;def&#34;&gt;&lt;b&gt;Definition:&lt;/b&gt; &lt;em&gt;An error&lt;/em&gt; is when the program is operating outside the intended path
of execution.&lt;/blockquote&gt;

&lt;p&gt;Running programs within the intended path of execution is a goal by
definition.  To track and reach this goal, we need to make it
observable whether the program is running healthily:&lt;/p&gt;
&lt;blockquote class=&#34;rule&#34;&gt;&lt;b&gt;Rule:&lt;/b&gt; All errors should be &lt;em&gt;observable&lt;/em&gt; from &lt;em&gt;the outside&lt;/em&gt;.&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Observable&lt;/em&gt; in this context means that it&amp;rsquo;s possible to bring the
error to a human&amp;rsquo;s attention (e.g. end user, system administrator,
developer) in an automated fashion.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The outside&lt;/em&gt; is defined by the bounds of your program.  The error
reports need to be made accessible to the surrounding environment,
so that stakeholders can access them.&lt;/p&gt;
&lt;h2 id=&#34;error-stakeholders&#34;&gt;Error stakeholders&lt;/h2&gt;
&lt;p&gt;The stakeholders for an error are the people involved in the software
lifecycle, such as: End users, developers, system administrators,
network administrators etc.&lt;/p&gt;
&lt;blockquote class=&#34;rule&#34;&gt;&lt;b&gt;Rule:&lt;/b&gt; For each error, there is a corresponding stakeholder.&lt;/blockquote&gt;

&lt;figure&gt;&lt;img src=&#34;https://blog.gnoack.org/images/stakeholders.svg&#34;
         alt=&#34;Different errors have different stakeholders who can address the issue.&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Different errors have different stakeholders who can address the issue.&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Is the error cause &lt;strong&gt;within the program itself&lt;/strong&gt;, then the
&lt;strong&gt;developer&lt;/strong&gt; is the stakeholder.&lt;/p&gt;
&lt;p&gt;Is the error cause &lt;strong&gt;in the user input or interaction&lt;/strong&gt; (e.g. invalid
input), then &lt;strong&gt;the user&lt;/strong&gt; is the stakeholder.&lt;/p&gt;
&lt;p&gt;Is the error cause &lt;strong&gt;in the execution environment&lt;/strong&gt;, then &lt;strong&gt;the
operator of that environment&lt;/strong&gt; is the stakeholder (e.g. sysadmin,
network admin, SRE).&lt;/p&gt;
&lt;h1 id=&#34;mechanisms&#34;&gt;Mechanisms&lt;/h1&gt;
&lt;h2 id=&#34;routing-errors-to-the-stakeholders&#34;&gt;Routing errors to the stakeholders&lt;/h2&gt;
&lt;p&gt;Routing error indicators to the right stakeholders is partially done
in code, and partially within the deployment.  Particularly,
displaying errors to end users is usually done in the program code
itself.  On the other hand, metrics collection set-ups can be
monitored by developers and administrators alike.&lt;/p&gt;
&lt;p&gt;There are two main strategies to make errors observable:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Propagate the error upwards towards the initiator of the erroring
operation.&lt;/li&gt;
&lt;li&gt;Propagate the error to the side (monitoring and logging).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At least one of these should be used for any error.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://blog.gnoack.org/images/errors.svg&#34;
         alt=&#34;A function can propagate errors upwards or to the side,
at least one of these should be used.&#34;/&gt;&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;
&lt;/figure&gt;

&lt;h2 id=&#34;propagating-an-error-upwards&#34;&gt;Propagating an error upwards&lt;/h2&gt;
&lt;p&gt;Propagating &amp;ldquo;upwards&amp;rdquo; moves the responsibility of error handling to a
higher level.  In general, higher level software has more context for
the failing operation, so they are often in a better position to route
the error in the right direction.&lt;/p&gt;
&lt;p&gt;Propagating errors upwards can take many forms.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Function level: &lt;strong&gt;Propagate to the calling procedure&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Return an error code&lt;/li&gt;
&lt;li&gt;Raise an exception&lt;/li&gt;
&lt;li&gt;Propagate a lower-level exception&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Process level: &lt;strong&gt;Crash the process&lt;/strong&gt;
&lt;ul&gt;
&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;
&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;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Network level: &lt;strong&gt;Return the error in a network response&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;User level: &lt;strong&gt;Show the error to the user&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;e.g. in a UI dialog&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class=&#34;info&#34;&gt;&lt;strong&gt;Note:&lt;/strong&gt; Remember to convert the error into a
representation which fits the level of abstraction that the caller
expects.  Many languages support nesting (wrapping) errors so that the
full context is retained.&lt;/blockquote&gt;

&lt;h2 id=&#34;propagating-an-error-to-the-side&#34;&gt;Propagating an error to the side&lt;/h2&gt;
&lt;p&gt;Sometimes passing the error upwards is not an option or not
sufficient, for example because you want to transparently recover or
hide a subsystem failure from the user.&lt;/p&gt;
&lt;p&gt;Propagating errors to the side can be one of the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Increment a counter which can be monitored from the outside.
(e.g. using Prometheus or Linux kernel stats counters)&lt;/li&gt;
&lt;li&gt;Write the error to an error collection service.
&lt;ul&gt;
&lt;li&gt;For server side software: Record stack traces and notify
developers about them.&lt;/li&gt;
&lt;li&gt;For client side software: Ask the user to send bug reports when
errors are encountered.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Make sure that all the relevant error propagation sinks are
monitored by the right stakeholders during the program&amp;rsquo;s operation.&lt;/p&gt;
&lt;p&gt;Systems like Prometheus are built with monitoring and alerting in
mind.  It&amp;rsquo;s often a good idea to alert on symptoms close to your
business needs and then use collected metrics on other errors for
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;
&lt;blockquote class=&#34;warning&#34;&gt;&lt;strong&gt;Warning:&lt;/strong&gt; Textual logging is not an error handling
strategy. Logs are not meant for machine consumption, so it&amp;rsquo;s hard to
have automated monitoring based on them.&lt;/blockquote&gt;

&lt;blockquote class=&#34;warning&#34;&gt;&lt;strong&gt;Warning:&lt;/strong&gt; Ignoring errors is not an error handling
strategy either.&lt;/blockquote&gt;

&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;
&lt;p&gt;If your case it not a fit, it&amp;rsquo;s possible that the condition at hand
might not be an error to begin with, but is maybe only a &amp;ldquo;corner case&amp;rdquo;
which may happen in normal operation (e.g. a lookup key was not
found).&lt;/p&gt;
&lt;p&gt;Consider switching the way that the condition is propagated.  The
following options are alternatives where otherwise errors may be
used.&lt;/p&gt;
&lt;ul&gt;
&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;
types, or other &lt;a href=&#34;https://en.wikipedia.org/wiki/Null_object_pattern&#34;&gt;Null
Objects&lt;/a&gt;. Note
that this is not the same as &lt;code&gt;null&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Separate channel:&lt;/strong&gt; Return the non-error conditions through a
separate channel (e.g. don&amp;rsquo;t use an exception, but return
specially-built objects for these conditions).  &lt;strong&gt;Example:&lt;/strong&gt; A
linter tool&amp;rsquo;s output is produced as part of the expected operation
and is therefore not an error within that context.&lt;/li&gt;
&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
too, but may lead to follow-up
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;
when the value is dereferenced.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class=&#34;info&#34;&gt;If none of these worked for you, I&amp;rsquo;d love to hear from you,
so I can correct my understanding.&lt;/blockquote&gt;

&lt;p&gt;Sometimes the most elegant solution is to &lt;strong&gt;change the API to make the
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
one that&amp;rsquo;s statically guaranteed by the type system, or change to
idempotent operation semantics, so that multiple invocations do not
conflict with each other.&lt;/p&gt;
&lt;h1 id=&#34;examples&#34;&gt;Examples&lt;/h1&gt;
&lt;p&gt;These are all written from the perspective of a piece of code
detecting an error.&lt;/p&gt;
&lt;h2 id=&#34;recovery-through-redundancy&#34;&gt;Recovery through redundancy&lt;/h2&gt;
&lt;h3 id=&#34;example&#34;&gt;Example&lt;/h3&gt;
&lt;p&gt;A disk in a software RAID is failing.&lt;/p&gt;
&lt;h3 id=&#34;stakeholder&#34;&gt;Stakeholder&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The system administrator&lt;/strong&gt;, as soon as the percentage of recovered executions &amp;gt; threshold.
They can then investigate the cause of network issues, exchange hard
drives or similar.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;mechanism&#34;&gt;Mechanism&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Recover&lt;/strong&gt; by retrying the operation on a different disk.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Increment an error counter&lt;/strong&gt; indicating the failure cause.  When
incremented in a monitorable system, this counter can trigger an alert.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;similar-cases&#34;&gt;Similar cases&lt;/h3&gt;
&lt;p&gt;A TCP network packet is lost. (Difference: Retry has less control over
the network routing)&lt;/p&gt;
&lt;h2 id=&#34;recovery-through-omission&#34;&gt;Recovery through omission&lt;/h2&gt;
&lt;h3 id=&#34;example-1&#34;&gt;Example&lt;/h3&gt;
&lt;p&gt;A web server uses multiple database backends.  One of the
non-essential backends starts to return errors.&lt;/p&gt;
&lt;h3 id=&#34;stakeholder-1&#34;&gt;Stakeholder&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;operator&lt;/strong&gt; of the failing subsystem.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;mechanism-1&#34;&gt;Mechanism&lt;/h3&gt;
&lt;ul&gt;
&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;
&lt;li&gt;&lt;strong&gt;Increment an error counter&lt;/strong&gt; indicating the failure cause, so that
the subsystem operator can be alerted.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;delegating-the-decision-to-the-calling-procedure&#34;&gt;Delegating the decision to the calling procedure&lt;/h2&gt;
&lt;h3 id=&#34;example-2&#34;&gt;Example&lt;/h3&gt;
&lt;p&gt;The Unix &lt;code&gt;open()&lt;/code&gt; function is asked to open a given filename for
reading, but the file doesn&amp;rsquo;t exist.&lt;/p&gt;
&lt;h3 id=&#34;stakeholder-2&#34;&gt;Stakeholder&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;We don&amp;rsquo;t know&lt;/strong&gt; who is responsible for passing the wrong filename,
but somewhere in the call chain, someone is going to know where that
filename comes from.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;mechanism-2&#34;&gt;Mechanism&lt;/h3&gt;
&lt;ul&gt;
&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;
&lt;/ul&gt;
&lt;h3 id=&#34;similar-cases-1&#34;&gt;Similar cases&lt;/h3&gt;
&lt;p&gt;Mistakes in passed input values are best handled by the code which
passed them, and which can judge why they happened.&lt;/p&gt;
&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;
&lt;h3 id=&#34;example-3&#34;&gt;Example&lt;/h3&gt;
&lt;p&gt;A web server&amp;rsquo;s servlets are returning errors in the form of HTTP
status codes.&lt;/p&gt;
&lt;h3 id=&#34;stakeholders&#34;&gt;Stakeholders&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;requester&lt;/strong&gt; is a stakeholder because they care about the
request.&lt;/li&gt;
&lt;li&gt;The web server&amp;rsquo;s &lt;strong&gt;operator&lt;/strong&gt; is a stakeholder because they care
about keeping overall error fractions within reasonable bounds.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;mechanisms-1&#34;&gt;Mechanisms&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Propagate status via HTTP&lt;/strong&gt;, upwards to the caller who has more
context.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Count HTTP statuses&lt;/strong&gt; keyed by relevant criteria (such as
servlet), e.g. in Prometheus, for the web server operator.&lt;/li&gt;
&lt;/ul&gt;
&lt;section class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34; role=&#34;doc-endnote&#34;&gt;
&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;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34; role=&#34;doc-endnote&#34;&gt;
&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;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34; role=&#34;doc-endnote&#34;&gt;
&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;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
    </item>
    
    <item>
      <title>There are my core dumps!</title>
      <link>https://blog.gnoack.org/post/there-are-my-core-dumps/</link>
      <pubDate>Sun, 02 Oct 2016 16:45:00 +0100</pubDate>
      
      <guid>https://blog.gnoack.org/post/there-are-my-core-dumps/</guid>
      <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
before&lt;/a&gt;,
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
sinks, instead of being stored to the current directory. By now, they
are recoverable by normal users again.&lt;/p&gt;
&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;
&lt;p&gt;Related bug about disappearing coredumps:
&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;
&lt;p&gt;Scenario: A simple program that crashes with a segfault:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;~/dumpcore$ cat dumpcore.c
#include &amp;lt;unistd.h&amp;gt;
void dump_core()   { int* boom = NULL; *boom = 2000; }
void its_time_to() { dump_core(); }
int main()         { its_time_to(); }
~/dumpcore$ cc -g -o dumpcore dumpcore.c
~/dumpcore$ ./dumpcore
Segmentation fault (core dumped)
&lt;/code&gt;&lt;/pre&gt;
&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;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;~/dumpcore$ coredumpctl list
TIME                            PID   UID   GID SIG PRESENT EXE
...
Sun 2016-10-02 14:44:14 CEST   3857  1000   100  11 * /home/me/dumpcore/dumpcore
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By default, &lt;code&gt;coredumpctl&lt;/code&gt; seems to use the most recent core dump,
so that you can easily inspect the most recent core dump with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;~/dumpcore$ coredumpctl gdb
           PID: 3857 (dumpcore)
           UID: 1000 (me)
           GID: 100 (users)
        Signal: 11 (SEGV)
     Timestamp: Sun 2016-10-02 14:44:14 CEST (1min 3s ago)
  Command Line: ./dumpcore
    Executable: /home/me/dumpcore/dumpcore
 Control Group: /user.slice/user-1000.slice/user@1000.service/gnome-terminal-server.service
          Unit: user@1000.service
     User Unit: user@1000.service
         Slice: user-1000.slice
     Owner UID: 1000 (me)
       Boot ID: 73902fbce4e241f5bab007aad96895eb
    Machine ID: 3ff4d30a94914397acd6af26eed15114
      Hostname: limbo
      Coredump: /var/lib/systemd/coredump/core.dumpcore.1000.73902fbce4e241f5bab007aad96895eb.3857.1475412254000000000000.lz4
       Message: Process 3857 (dumpcore) of user 1000 dumped core.

                Stack trace of thread 3857:
                #0  0x00000000004004b6 dump_core (dumpcore)
                #1  0x00000000004004cd its_time_to (dumpcore)
                #2  0x00000000004004de main (dumpcore)
                #3  0x00007f89ba351291 __libc_start_main (libc.so.6)
                #4  0x00000000004003da _start (dumpcore)

GNU gdb (GDB) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later &amp;lt;http://gnu.org/licenses/gpl.html&amp;gt;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type &amp;quot;show copying&amp;quot;
and &amp;quot;show warranty&amp;quot; for details.
This GDB was configured as &amp;quot;x86_64-pc-linux-gnu&amp;quot;.
Type &amp;quot;show configuration&amp;quot; for configuration details.
For bug reporting instructions, please see:
&amp;lt;http://www.gnu.org/software/gdb/bugs/&amp;gt;.
Find the GDB manual and other documentation resources online at:
&amp;lt;http://www.gnu.org/software/gdb/documentation/&amp;gt;.
For help, type &amp;quot;help&amp;quot;.
Type &amp;quot;apropos word&amp;quot; to search for commands related to &amp;quot;word&amp;quot;...
Reading symbols from /home/me/dumpcore/dumpcore...done.
[New LWP 3857]

warning: Could not load shared library symbols for linux-vdso.so.1.
Do you need &amp;quot;set solib-search-path&amp;quot; or &amp;quot;set sysroot&amp;quot;?
Core was generated by `./dumpcore&#39;.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00000000004004b6 in dump_core () at dumpcore.c:2
2	void dump_core()   { int* boom = NULL; *boom = 2000; }
(gdb) bt
#0  0x00000000004004b6 in dump_core () at dumpcore.c:2
#1  0x00000000004004cd in its_time_to () at dumpcore.c:3
#2  0x00000000004004de in main () at dumpcore.c:4
(gdb)
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>GPG with the CCID Driver</title>
      <link>https://blog.gnoack.org/post/gpg-ccid/</link>
      <pubDate>Mon, 15 Aug 2016 12:00:00 +0100</pubDate>
      
      <guid>https://blog.gnoack.org/post/gpg-ccid/</guid>
      <description>&lt;p&gt;Unless you&amp;rsquo;re using Debian, where people care about this, chances are
that setting up GPG Smartcards with your Linux distribution is an
adventure.  There are two ways to do it, CCID and PCSCLite, the latter
of which runs a background service &lt;code&gt;pcscd&lt;/code&gt; &amp;ndash; as root, at least on Arch,
while GnuPG&amp;rsquo;s built-in CCID driver accesses the reader directly
through the USB device, but took me a lot longer to figure out how to
use.&lt;/p&gt;
&lt;h2 id=&#34;problem&#34;&gt;Problem&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;re getting a &amp;ldquo;card error&amp;rdquo; when trying to access the card.  The
same thing works as root.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ gpg --card-status
gpg: selecting openpgp failed: Card error
gpg: OpenPGP card not available: Card error
$
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When trying the same as root, you can access the card.&lt;/p&gt;
&lt;h2 id=&#34;solution&#34;&gt;Solution&lt;/h2&gt;
&lt;p&gt;Add a &lt;code&gt;udev&lt;/code&gt; rule that changes file permissions for you, as documented on
&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;
&lt;p&gt;Add your user to a new user group that can read smartcards, and give
that group read-write access to the device when it&amp;rsquo;s plugged in, by
creating a file &lt;code&gt;/etc/udev/rules.d&lt;/code&gt; with the rule:&lt;/p&gt;
&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;
&lt;/code&gt;&lt;/pre&gt;
&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;
</description>
    </item>
    
    <item>
      <title>Hexiamonds</title>
      <link>https://blog.gnoack.org/post/hexiamonds/</link>
      <pubDate>Sun, 05 Jun 2016 12:00:00 +0100</pubDate>
      
      <guid>https://blog.gnoack.org/post/hexiamonds/</guid>
      <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;
&lt;p&gt;Each Hexiamond piece consists of 6 triangles, which yields 12
different pieces when you try out all combinations.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://blog.gnoack.org/post/hexiamonds/images/hexiamond.png&#34;
         alt=&#34;3d model of a Hexiamond&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;3d model of a Hexiamond&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;More background information and some interesting puzzles to try can be
found on this nice page by David Goodger:
&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;
</description>
    </item>
    
    <item>
      <title>Python-like generator functions</title>
      <link>https://blog.gnoack.org/post/generators/</link>
      <pubDate>Sun, 16 Nov 2014 19:41:00 +0100</pubDate>
      
      <guid>https://blog.gnoack.org/post/generators/</guid>
      <description>&lt;p&gt;Python-like generator functions, implemented as a library:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://blog.gnoack.org/post/generators/images/fn-generators.png&#34;
         alt=&#34;Generator functions implemented as a library&#34;/&gt;&lt;figcaption&gt;
            &lt;p&gt;Generator functions implemented as a library&lt;/p&gt;
        &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This is possible through two simple tricks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The language represents stack frames as objects on the heap.&lt;/li&gt;
&lt;li&gt;There&amp;rsquo;s a native function for grabbing the current stack frame.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Turns out replacing the calling stack frame is really the only thing
you need in order to implement coroutines and generics.&lt;/p&gt;
&lt;p&gt;The implementation is only 23 lines long.  On my screen, including the
screenshot, this weblog article is already longer up until here.&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
