<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Kiril Vladimirov</title>
    <link>https://vld.bg/</link>
    <description>Recent content on Kiril Vladimirov</description>
    <generator>Hugo -- 0.140.2</generator>
    <language>en</language>
    <lastBuildDate>Wed, 20 Nov 2024 20:45:51 +0200</lastBuildDate>
    <atom:link href="https://vld.bg/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>To race the mount</title>
      <link>https://vld.bg/articles/to-race-the-mount/</link>
      <pubDate>Wed, 20 Nov 2024 20:45:51 +0200</pubDate>
      <guid>https://vld.bg/articles/to-race-the-mount/</guid>
      <description>&lt;p&gt;This is one of those frustrating debug stories that makes you pull your hair
out until you suddenly figure it out. The relief you feel afterwards is one of
the reasons I love programming so much.&lt;/p&gt;
&lt;p&gt;We were running an internal implementation of a &lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc5424&#34; target=&#34;_blank&#34;&gt;syslog&lt;/a&gt;
 server in Go, receiving
the logs of a bunch of machines in the same datacenter (i.e. internal network).
That server was setup to run on boot, receive the logs on UDP port 514, do a
bunch of things with them and eventually writing them down into &lt;code&gt;/var/log/foo&lt;/code&gt;.
Nothing complicated nor extraordinary.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>This is one of those frustrating debug stories that makes you pull your hair
out until you suddenly figure it out. The relief you feel afterwards is one of
the reasons I love programming so much.</p>
<p>We were running an internal implementation of a <a href="https://datatracker.ietf.org/doc/html/rfc5424" target="_blank">syslog</a>
 server in Go, receiving
the logs of a bunch of machines in the same datacenter (i.e. internal network).
That server was setup to run on boot, receive the logs on UDP port 514, do a
bunch of things with them and eventually writing them down into <code>/var/log/foo</code>.
Nothing complicated nor extraordinary.</p>
<p>We were running happily with that for a few years, until an OS upgrade came
around the corner. Given that the service was doing nothing special, nobody
believed it would cause any issues whatsoever. Building the package for the new
OS was a no brainer, nor was building the machine&rsquo;s image. Upgrade day comes
and everything is running fine, except that <code>/var/log/foo/foo.log</code> is missing.
Weird.</p>
<p>According to the service&rsquo;s logs everything was running. Packages were flowing
on that port, according to <code>tcpdump</code> and even the expected occasional CPU
little spikes were there. Directory was still empty, though. Given that this
service is written in Go, sending a mere <a href="https://man7.org/linux/man-pages/man3/abort.3.html" target="_blank">ABRT</a>
 signal caused it to dump useful
stack trace to STDERR and terminate. Judging by the traces - the service was
running fine, multiple goroutines, running fine and doing their job. Where are
the logs, though?</p>
<p>Opening that <code>foo.log</code> file inside <code>/var/log/foo</code> is one of the first things that this program did, so one would even expect it to have that file opened as FD 3 and sure enough, judging by the opened file descriptors by this process, as reported by <a href="https://man7.org/linux/man-pages/man5/proc.5.html" target="_blank">procfs</a>
, that&rsquo;s precisely the case:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;display:grid;"><code class="language-plain" data-lang="plain"><span style="display:flex;"><span>❯ ls -la /proc/1801/fd
</span></span><span style="display:flex;"><span>lrwx------ 1 root root 64 Nov 20 09:07 0 -&gt; /dev/null
</span></span><span style="display:flex;"><span>l-wx------ 1 root root 64 Nov 20 09:07 1 -&gt; &#39;pipe:[22087]&#39;
</span></span><span style="display:flex;"><span>l-wx------ 1 root root 64 Nov 20 09:07 2 -&gt; &#39;pipe:[22087]&#39;
</span></span><span style="display:flex; background-color:#363636"><span>l-wx------ 1 root root 64 Nov 20 09:05 3 -&gt; /var/log/foo/foo.log
</span></span><span style="display:flex;"><span>lrwx------ 1 root root 64 Nov 20 09:07 4 -&gt; &#39;anon_inode:[eventpoll]&#39;
</span></span><span style="display:flex;"><span>lr-x------ 1 root root 64 Nov 20 09:07 5 -&gt; &#39;pipe:[25179]&#39;
</span></span><span style="display:flex;"><span>l-wx------ 1 root root 64 Nov 20 09:07 6 -&gt; &#39;pipe:[25179]&#39;
</span></span><span style="display:flex;"><span>lrwx------ 1 root root 64 Nov 20 09:07 7 -&gt; &#39;socket:[24122]&#39;
</span></span><span style="display:flex;"><span>lrwx------ 1 root root 64 Nov 20 09:07 8 -&gt; &#39;socket:[41476]&#39;
</span></span><span style="display:flex;"><span>lrwx------ 1 root root 64 Nov 20 09:07 9 -&gt; &#39;socket:[41477]&#39;
</span></span><span style="display:flex;"><span>[..]
</span></span></code></pre></div><p>Okay, the file is opened properly, but no logs are ever written. Given that remote communication is involved here, it was easy to blame &ldquo;The network&rdquo;™.  Our  working hypothesis at point is just something getting stuck waiting for something to happen. Or probably writing down into the file failed? But where are the error messages about it? <code>strace</code> to the rescue:</p>
<pre tabindex="0"><code>❯ strace -p 1801 -f -s 4096 -e write -e fd=3
[pid  1802] write(3, &#34;logline 1...\n&#34;, 232 &lt;unfinished ...&gt;
[pid  1801] write(3, &#34;logline 2...\n&#34;, 322 &lt;unfinished ...&gt;
[pid  4902] write(3, &#34;logline 3...\n&#34;, 581 &lt;unfinished ...&gt;
[pid  4902] write(3, &#34;logline 4...\n&#34;, 273 &lt;unfinished ...&gt;
[pid  4902] write(3, &#34;logline 5...\n&#34;, 149 &lt;unfinished ...&gt;
[pid  4903] write(3, &#34;logline 6...\n&#34;, 485 &lt;unfinished ...&gt;
[..]
</code></pre><p>Let&rsquo;s just break down what we&rsquo;re seeing here, as <a href="https://man7.org/linux/man-pages/man1/strace.1.html" target="_blank">strace(1)</a>
 might not be that popular as I seem to believe, based on a few recent conversations outside of this scope:</p>
<ul>
<li><code>-p 1801</code> - intercept system calls performed by the process with PID 1801 (our server&rsquo;s main process)</li>
<li><code>-f</code> - follow all threads of this process and child processes as well. This is a Go program after all, surely there are multiple threads and processes.</li>
<li><code>-s 4096</code> - we are hunting for log messages, so dump strings up to 4096 bytes (instead of the default 32)</li>
<li><code>-e write</code> - trace only <a href="https://man7.org/linux/man-pages/man2/write.2.html" target="_blank">write(2)</a>
 syscalls</li>
<li><code>-e fd=3</code> - trace only syscalls that operate on file descriptor 3, which we know is our empty file, as seen above</li>
</ul>
<p>I&rsquo;ve truncated the output and log messages here, but there were pages of those. We are clearly observing log messages being written precisely into that file, from multiple goroutines without a failure, judging by the positive results of the syscalls. Where do they go? Why is the file missing? To make things even more annoying - restarting the service made the issue go away. It&rsquo;s only observed on first boot. Once everybody&rsquo;s tools for inspection are in place, things just worked.</p>
<p>Code works, service is available, packets fly, logs are being written. Just&hellip; files are missing. Assuming the code is fine. Let&rsquo;s observe the environment deeper.  <a href="https://man7.org/linux/man-pages/man5/proc.5.html" target="_blank">procfs</a>
 has way more to tell here.</p>
<p>Could the processes have another idea what is <code>/var/log/foo</code> from the rest of the world? This is what namespaces do in the linux world to begin with. Looking into <a href="https://man7.org/linux/man-pages/man5/proc_pid_ns.5.html" target="_blank">/proc/{PID}/ns</a>
 completely disproved that:</p>
<pre tabindex="0"><code>❯ ls -l /proc/1801/ns/mnt
lrwxrwxrwx 1 root root 0 Nov 20 09:16 /proc/1684/ns/mnt -&gt; &#39;mnt:[4026531841]&#39;
❯ ls -l /proc/$$/ns/mnt
lrwxrwxrwx 1 root root 0 Nov 20 09:16 /proc/6561/ns/mnt -&gt; &#39;mnt:[4026531841]&#39;
</code></pre><p><code>$$</code> is the PID of the current process of the shell. Clearly it sees the same mount namespace as our service. But how come does the shell see different contents? However, we know that there is disk mounted into <code>/var/log/foo</code>, let&rsquo;s see the <a href="https://man7.org/linux/man-pages/man5/proc_pid_mountinfo.5.html" target="_blank">proc&rsquo;s mountinfo</a>
:</p>
<pre tabindex="0"><code>❯ cat /proc/1801/mountinfo | grep /var/log
516 66 8:16 / /var/log/foo rw,relatime shared:192 - ext4 /dev/sdb rw
❯ cat /proc/$$/mountinfo | grep /var/log
516 66 8:16 / /var/log/foo rw,relatime shared:192 - ext4 /dev/sdb rw
</code></pre><p>Okay, we both see the same mount with ID 516, mounted over <code>/</code> which ID is apparently 66. How come only the process see that ghost file that nobody else is observing? Let&rsquo;s look into that file a bit more. Apart from <a href="https://man7.org/linux/man-pages/man5/proc_pid_fd.5.html" target="_blank">/proc/{PID}/fd</a>
 which merely lists file descriptors and helps distinguish their type and location, there&rsquo;s also <a href="https://man7.org/linux/man-pages/man5/proc_pid_fdinfo.5.html" target="_blank">/proc/{PID}/fdinfo</a>
 which gives detailed information about each file descriptor:</p>
<pre tabindex="0"><code>❯ cat /proc/1801/fdinfo/3
pos:    218105
flags:  02102001
mnt_id: 66
ino:    132368
</code></pre><p>Eureka! <code>mnt_id: 66</code>. Remember that this was <code>/</code>, according to <a href="https://man7.org/linux/man-pages/man5/proc_pid_mountinfo.5.html" target="_blank">mountinfo</a>
? How on earth is that file in the root filesystem, given that there is something else mounted in there, you might ask? Well, as I said - this only happens on first boot. If the service is restarted, everything runs smooth again. Apparently, this service starts way too soon, even before the mount is finished.</p>
<p>And sure enough. It indeed starts too soon&hellip; by a single damn second:</p>
<pre tabindex="0"><code>❯ journalctl -b | grep &#39;/var/log/foo&#39;
Nov 20 08:28:31 systemd[1]: var-log-foo.mount: Directory /var/log/foo to mount over is not empty, mounting anyway.
Nov 20 08:28:31 systemd[1]: Mounting /var/log/foo...
Nov 20 08:28:34 systemd[1]: Mounted /var/log/foo.

❯ ps -p 1801 -o lstart
Wed Nov 20 08:28:30 2024:    132368
</code></pre><h2 id="what-are-the-odds-of-this">What are the odds of this!?</h2>
<p>&hellip; you might ask. Well, given that this machine boots from an image, it was happening every single time, we&rsquo;ve tried. How come it never happened before - I don&rsquo;t know. Different kernel, different systemd (where backwards compatibility does not mean a lot to begin with), different&hellip; who knows what.</p>
<p>The point is to know your tools and running environment well enough to be able to dig into this quick enough, regardless of what time it is.</p>
<blockquote>
<p>Good programmers know what they’re doing. Great programmers understand one level deeper.</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>Retrieving file timestamps in Go</title>
      <link>https://vld.bg/articles/go-stat/</link>
      <pubDate>Sun, 19 May 2024 23:02:28 +0300</pubDate>
      <guid>https://vld.bg/articles/go-stat/</guid>
      <description>&lt;p&gt;Recently, a friend of mine needed to get the creation time of a file in a Go
project. There&amp;rsquo;s &lt;a href=&#34;https://pkg.go.dev/os#Stat&#34; target=&#34;_blank&#34;&gt;os.Stat&lt;/a&gt;
, so how hard can it be,
right?&lt;/p&gt;
&lt;p&gt;&lt;code&gt;os.Stat&lt;/code&gt; returns &lt;a href=&#34;https://pkg.go.dev/io/fs#FileInfo&#34; target=&#34;_blank&#34;&gt;fs.FileInfo&lt;/a&gt;
 which is an
interface with six methods:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#6ab825;font-weight:bold&#34;&gt;type&lt;/span&gt; FileInfo &lt;span style=&#34;color:#6ab825;font-weight:bold&#34;&gt;interface&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#447fcf&#34;&gt;Name&lt;/span&gt;() &lt;span style=&#34;color:#6ab825;font-weight:bold&#34;&gt;string&lt;/span&gt;       &lt;span style=&#34;color:#999;font-style:italic&#34;&gt;// base name of the file
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#999;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#447fcf&#34;&gt;Size&lt;/span&gt;() &lt;span style=&#34;color:#6ab825;font-weight:bold&#34;&gt;int64&lt;/span&gt;        &lt;span style=&#34;color:#999;font-style:italic&#34;&gt;// length in bytes for regular files; [..]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#999;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#447fcf&#34;&gt;Mode&lt;/span&gt;() FileMode     &lt;span style=&#34;color:#999;font-style:italic&#34;&gt;// file mode bits
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#999;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#447fcf&#34;&gt;ModTime&lt;/span&gt;() time.Time &lt;span style=&#34;color:#999;font-style:italic&#34;&gt;// modification time
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#999;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#447fcf&#34;&gt;IsDir&lt;/span&gt;() &lt;span style=&#34;color:#6ab825;font-weight:bold&#34;&gt;bool&lt;/span&gt;        &lt;span style=&#34;color:#999;font-style:italic&#34;&gt;// abbreviation for Mode().IsDir()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#999;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#447fcf&#34;&gt;Sys&lt;/span&gt;() any           &lt;span style=&#34;color:#999;font-style:italic&#34;&gt;// underlying data source (can return nil)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#999;font-style:italic&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Time of last modification (mtime) is the only time reported by this interface,
though. There is no time of last access (atime), creation (btime), nor status
change (ctime).&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Recently, a friend of mine needed to get the creation time of a file in a Go
project. There&rsquo;s <a href="https://pkg.go.dev/os#Stat" target="_blank">os.Stat</a>
, so how hard can it be,
right?</p>
<p><code>os.Stat</code> returns <a href="https://pkg.go.dev/io/fs#FileInfo" target="_blank">fs.FileInfo</a>
 which is an
interface with six methods:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">type</span> FileInfo <span style="color:#6ab825;font-weight:bold">interface</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#447fcf">Name</span>() <span style="color:#6ab825;font-weight:bold">string</span>       <span style="color:#999;font-style:italic">// base name of the file
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span>	<span style="color:#447fcf">Size</span>() <span style="color:#6ab825;font-weight:bold">int64</span>        <span style="color:#999;font-style:italic">// length in bytes for regular files; [..]
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span>	<span style="color:#447fcf">Mode</span>() FileMode     <span style="color:#999;font-style:italic">// file mode bits
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span>	<span style="color:#447fcf">ModTime</span>() time.Time <span style="color:#999;font-style:italic">// modification time
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span>	<span style="color:#447fcf">IsDir</span>() <span style="color:#6ab825;font-weight:bold">bool</span>        <span style="color:#999;font-style:italic">// abbreviation for Mode().IsDir()
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span>	<span style="color:#447fcf">Sys</span>() any           <span style="color:#999;font-style:italic">// underlying data source (can return nil)
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span>}
</span></span></code></pre></div><p>Time of last modification (mtime) is the only time reported by this interface,
though. There is no time of last access (atime), creation (btime), nor status
change (ctime).</p>
<h2 id="sys">Sys()</h2>
<p>Did you notice that <code>Sys()</code> method there? Yeah, me neither. This poorly
documented method returns raw data for that file, as returned by the operating
system. That means the underlying type of the result will be different per-OS.
In our case, it&rsquo;s a software intended to run exclusively on linux, so let&rsquo;s see
what happens there.</p>
<p>Well, in Linux, it returns a pointer to <a href="https://pkg.go.dev/syscall#Stat_t" target="_blank">syscall.Stat_t</a>
:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">type</span> Stat_t <span style="color:#6ab825;font-weight:bold">struct</span> {
</span></span><span style="display:flex;"><span>	Dev       <span style="color:#6ab825;font-weight:bold">uint64</span>
</span></span><span style="display:flex;"><span>	Ino       <span style="color:#6ab825;font-weight:bold">uint64</span>
</span></span><span style="display:flex;"><span>	Nlink     <span style="color:#6ab825;font-weight:bold">uint64</span>
</span></span><span style="display:flex;"><span>	Mode      <span style="color:#6ab825;font-weight:bold">uint32</span>
</span></span><span style="display:flex;"><span>	Uid       <span style="color:#6ab825;font-weight:bold">uint32</span>
</span></span><span style="display:flex;"><span>	Gid       <span style="color:#6ab825;font-weight:bold">uint32</span>
</span></span><span style="display:flex;"><span>	X__pad0   <span style="color:#6ab825;font-weight:bold">int32</span>
</span></span><span style="display:flex;"><span>	Rdev      <span style="color:#6ab825;font-weight:bold">uint64</span>
</span></span><span style="display:flex;"><span>	Size      <span style="color:#6ab825;font-weight:bold">int64</span>
</span></span><span style="display:flex;"><span>	Blksize   <span style="color:#6ab825;font-weight:bold">int64</span>
</span></span><span style="display:flex;"><span>	Blocks    <span style="color:#6ab825;font-weight:bold">int64</span>
</span></span><span style="display:flex;"><span>	Atim      Timespec
</span></span><span style="display:flex;"><span>	Mtim      Timespec
</span></span><span style="display:flex;"><span>	Ctim      Timespec
</span></span><span style="display:flex;"><span>	X__unused [<span style="color:#3677a9">3</span>]<span style="color:#6ab825;font-weight:bold">int64</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Great, we have atime, mtime and ctime. We&rsquo;ve almost declared a win, until
realizing that ctime is not creation time. It&rsquo;s the time of last status change,
which means it records any change of file&rsquo;s metadata. What we seek is creation
time a.k.a. birth time. Yep, I&rsquo;ve just used almost 300 words to tell you
that with <code>os.Stat</code> you can NOT get the creation time of a file.</p>
<h1 id="statx2">statx(2)</h1>
<p>To be fair, you would not be able to get the creation time using stat in C,
either. Not to mention that most of the filesystems do not keep record of it.
That was surprising to me - fat32, ext2, ext3 nor reiserfs store when a file
has been created. Naturally, no such information is exposed by stat(2).
Modern filesystems do, though.</p>
<p>After years of planning a new system call is finally merged into the Linux kernel
and released with 4.11 in 2017. That&rsquo;s years after the first released version
of Go and five after 1.0. That explains why the standard library does not
provide a straightforward way to obtain btime.</p>
<h1 id="golangorgxsysunix">golang.org/x/sys/unix</h1>
<p>The standard library might be a bit conservative in adding new things (although
things are starting to move now with the new
<a href="https://go.dev/blog/randv2" target="_blank">math/rand/v2</a>
), but that does not mean the Go team
is sleeping. The <code>golang.org/x/</code> packages are outside the main Go tree and are
under way looser constraints for backwards compatibility. One of these packages
is <a href="https://pkg.go.dev/golang.org/x/sys/unix" target="_blank">golang.org/x/sys/unix</a>
. The <code>sys</code>
part is described as &ldquo;packages for making system calls&rdquo;, so do not expect the
easiest to use API you&rsquo;ve ever seen.</p>
<p>Sure enough, there&rsquo;s a wrapper function of the statx syscall:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">func</span> <span style="color:#447fcf">Statx</span>(dirfd <span style="color:#6ab825;font-weight:bold">int</span>, path <span style="color:#6ab825;font-weight:bold">string</span>, flags <span style="color:#6ab825;font-weight:bold">int</span>, mask <span style="color:#6ab825;font-weight:bold">int</span>, stat *Statx_t) (err <span style="color:#6ab825;font-weight:bold">error</span>)
</span></span></code></pre></div><p>As expected the API is pretty much the same as with the syscall it wraps:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">int</span> <span style="color:#447fcf">statx</span>(<span style="color:#6ab825;font-weight:bold">int</span> dirfd, <span style="color:#6ab825;font-weight:bold">const</span> <span style="color:#6ab825;font-weight:bold">char</span> *<span style="color:#6ab825;font-weight:bold">restrict</span> pathname, <span style="color:#6ab825;font-weight:bold">int</span> flags,
</span></span><span style="display:flex;"><span>          <span style="color:#6ab825;font-weight:bold">unsigned</span> <span style="color:#6ab825;font-weight:bold">int</span> mask, <span style="color:#6ab825;font-weight:bold">struct</span> statx *<span style="color:#6ab825;font-weight:bold">restrict</span> statxbuf);
</span></span></code></pre></div><ul>
<li>dirfd is a file descriptor identifying the directory to search from if
provided path is relative (if is <code>AT_FDCWD</code> the call operates on the
current working directory).</li>
<li>path is obviously the filename we&rsquo;re querying. Unless when empty and
<code>AT_EMPTY_PATH</code> is in mask, in that case file/directory pointed to by
dirfd is what we&rsquo;re querying.</li>
<li>flags can be used to influence a pathname-based lookup and what sort of
synchronization the kernel will do when querying. When in doubt, use
<code>AT_STATX_SYNC_AS_STAT</code>.</li>
<li>mask is used to tell which fields we are interested in, so that the kernel
does not bother populating the rest. The one we care about to is
<code>STATX_BTIME</code>. If it&rsquo;s there (or <code>STATX_ALL</code> which pretty much includes
everything), then the creation time will be there.</li>
<li>stat is being populated be the syscall when the returned error is nil.</li>
</ul>
<p>All of those <code>SCREAMING_SNAKE_CASE</code> flags listed above are exposed as constants in
the same package.</p>
<p><code>unix.Statx_t</code> is a fairly big struct (matching the statx struct obviously)
that has all of the timestamps we seek:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">type</span> Statx_t <span style="color:#6ab825;font-weight:bold">struct</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#999;font-style:italic">// ...
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span>	Atime            StatxTimestamp
</span></span><span style="display:flex;"><span>	Btime            StatxTimestamp
</span></span><span style="display:flex;"><span>	Ctime            StatxTimestamp
</span></span><span style="display:flex;"><span>	Mtime            StatxTimestamp
</span></span><span style="display:flex;"><span>    <span style="color:#999;font-style:italic">//..
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span>}
</span></span></code></pre></div><p><code>StatxTimestamp</code> has <code>Sec</code> and <code>Nsec</code> fields which is enough to create a
<code>time.Time</code> value using <code>time.Unix()</code>. So, the whole thing might look something
like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">var</span> statx unix.Statx_t
</span></span><span style="display:flex;"><span>err := unix.<span style="color:#447fcf">Statx</span>(unix.AT_FDCWD, name, unix.AT_STATX_SYNC_AS_STAT, unix.STATX_BTIME, &amp;statx)
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">if</span> err != <span style="color:#6ab825;font-weight:bold">nil</span> {
</span></span><span style="display:flex;"><span>    log.<span style="color:#447fcf">Fatal</span>(err)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>btime := time.<span style="color:#447fcf">Unix</span>(statx.Btime.Sec, <span style="color:#24909d">int64</span>(statx.Btime.Nsec))
</span></span><span style="display:flex;"><span>fmt.<span style="color:#447fcf">Printf</span>(<span style="color:#ed9d13">&#34;%s is created at %v\n&#34;</span>, name, btime)
</span></span></code></pre></div><h2 id="easy-right">Easy, right?</h2>
<p>Don&rsquo;t agree? Yeah, me neither. A saner person would just npm the problem and
look for a package exposing file times in a proper, easy-to-use way. I found
this, which looks legit (only checked for GOOS=linux):
<a href="https://github.com/djherbis/times" target="_blank">github.com/djherbis/times</a>
.</p>
<p>I mean it. A third-party package with a higher-level <strong>portable</strong> API is the
way to go in the real world. It&rsquo;s good to know what&rsquo;s happening underneath, but
please beware of NIH syndrome.</p>
<p>Achieving the same result in Python isn&rsquo;t much easier. The result from <code>os.stat</code>
might have a <code>st_birthtime</code> on some operating systems (e.g., FreeBSD or
Windows), but not on Linux. Sometimes seemingly trivial problems are tedious to
solve because of weird historical reasons. And sometimes, a deeper dive is
necessary, but practical solutions are often just a package away.</p>
]]></content:encoded>
    </item>
    <item>
      <title>4913 &#43;= 123</title>
      <link>https://vld.bg/articles/4913_123/</link>
      <pubDate>Mon, 11 Mar 2024 22:18:30 +0200</pubDate>
      <guid>https://vld.bg/articles/4913_123/</guid>
      <description>&lt;p&gt;With merely a handful of articles, I&amp;rsquo;m still growing into my confidence as a writer.
However, I&amp;rsquo;m obviously nailing it when it comes to titles, right? It will all
make sense in a moment.&lt;/p&gt;
&lt;p&gt;As I was writing my &lt;a href=&#34;https://vld.bg/tips/inotify/&#34;&gt;tip about inotifywait(1)&lt;/a&gt;
, decided to show
how different editors behave when saving a file. &amp;ldquo;I use vim btw&amp;rdquo;™, so it didn&amp;rsquo;t
take long to try it in there.&lt;/p&gt;
&lt;p&gt;Executed &lt;code&gt;vim foo +wq&lt;/code&gt; and this is what &lt;code&gt;inotifywait(1)&lt;/code&gt; printed:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>With merely a handful of articles, I&rsquo;m still growing into my confidence as a writer.
However, I&rsquo;m obviously nailing it when it comes to titles, right? It will all
make sense in a moment.</p>
<p>As I was writing my <a href="/tips/inotify/">tip about inotifywait(1)</a>
, decided to show
how different editors behave when saving a file. &ldquo;I use vim btw&rdquo;™, so it didn&rsquo;t
take long to try it in there.</p>
<p>Executed <code>vim foo +wq</code> and this is what <code>inotifywait(1)</code> printed:</p>
<pre tabindex="0"><code>/path/to/watched/dir/ CLOSE_WRITE,CLOSE 4913
/path/to/watched/dir/ DELETE 4913
/path/to/watched/dir/ MOVED_FROM foo
/path/to/watched/dir/ CLOSE_WRITE,CLOSE foo
</code></pre><p>That&rsquo;s weird. It creates a file named 4913 and then moves it to the intended
location. Why 4913, though? Tried it several times on multiple machines - always
that same number. You know how when it comes to some vim mystery, everybody
always tells you to use <code>:help</code>? Yeah, no luck there, this time.</p>
<h3 id="git-clone-httpsgithubcomvimvimgit--rg-4913-vim"><code>git clone https://github.com/vim/vim.git &amp;&amp; rg 4913 vim</code></h3>
<p>Two meaningful results.</p>
<blockquote>
<p><strong>vim/runtime/doc/version7.txt:</strong> On MS-Windows sometimes files with number 4913 or higher are left behind.</p>
</blockquote>
<p>😅</p>
<p>Fine. <a href="https://github.com/vim/vim/blob/473952e85286eb9c6098801f1819981ba61ad153/src/bufwrite.c#L1186" target="_blank">One meaningful result</a>
:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;display:grid;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#999;font-style:italic">// Check if we can create a file and set the owner/group to
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic">// the ones from the original file.
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic">// First find a file name that doesn&#39;t exist yet (use some
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic">// arbitrary numbers).
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span><span style="color:#447fcf">STRCPY</span>(IObuff, fname);
</span></span><span style="display:flex;"><span>fd = -<span style="color:#3677a9">1</span>;
</span></span><span style="display:flex; background-color:#363636"><span><span style="color:#6ab825;font-weight:bold">for</span> (i = <span style="color:#3677a9">4913</span>; ; i += <span style="color:#3677a9">123</span>)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#447fcf">sprintf</span>((<span style="color:#6ab825;font-weight:bold">char</span> *)<span style="color:#447fcf">gettail</span>(IObuff), <span style="color:#ed9d13">&#34;%d&#34;</span>, i);
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">if</span> (<span style="color:#447fcf">mch_lstat</span>((<span style="color:#6ab825;font-weight:bold">char</span> *)IObuff, &amp;st) &lt; <span style="color:#3677a9">0</span>)
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>    fd = <span style="color:#447fcf">mch_open</span>((<span style="color:#6ab825;font-weight:bold">char</span> *)IObuff,
</span></span><span style="display:flex;"><span>            O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm);
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">if</span> (fd &lt; <span style="color:#3677a9">0</span> &amp;&amp; errno == EEXIST)
</span></span><span style="display:flex;"><span>        <span style="color:#999;font-style:italic">// If the same file name is created by another
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span>        <span style="color:#999;font-style:italic">// process between lstat() and open(), find another
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span>        <span style="color:#999;font-style:italic">// name.
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span>        <span style="color:#6ab825;font-weight:bold">continue</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">break</span>;
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">if</span> (fd &lt; <span style="color:#3677a9">0</span>)	<span style="color:#999;font-style:italic">// can&#39;t write in directory
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span>    backup_copy = TRUE;
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">else</span> [..]
</span></span></code></pre></div><p>This is part of a (haunting) function bigger than 6000 lines called <code>int buf_write</code>. This particular block is only accessible when <code>:set backup</code> and the
user is trying to save changes in a file that already exists. So, the idea is
fairly simple: make sure to write the changes in any file whatsoever inside the
target directory in order to move it over the target file, so that the latter
will be updated atomically. No one would ever observe partial change of state.</p>
<p>But why 4913? Reminded me of a meme about that random function which always
returns 4, because it was a result of a perfectly fair dice throw. No idea, it
appeared in <a href="https://github.com/vim/vim/commit/071d4279d6ab81b7187b48f3a0fc61e587b6db6c" target="_blank">the 7th
commit</a>

since the migration to git for version 7. <strong>If anybody knows, please reach
out.</strong></p>
<p>The purpose of adding 123 until the end of time is clear, though. Pick &ldquo;a
random&rdquo; non-existent file to the target directory. Choosing 123 in particular
is there just because Bram had to write some number, probably. Doing this
indefinitely is not really a bad idea <strong>in this case</strong>. I mean, who in their
right mind will create thousands of files with names that are only numbers
starting from 4913 and then adding 123?</p>
<details>
    <summary> Well, me, apparently. (click to expand) </summary>
<p>Let&rsquo;s see how hard we can make it for vim. A single write over already existing
file does not take long even on pretty old hardware (Xeon E5-2690):</p>
<pre tabindex="0"><code>$ time vim files/foo +wq

real    0m0.035s
user    0m0.015s
sys     0m0.012s
</code></pre><p>Let&rsquo;s see what happens when 4913 exists:</p>
<pre tabindex="0"><code>$ touch files/4913 &amp;&amp; time vim files/foo +wq

real    0m0.034s
user    0m0.021s
sys     0m0.004s
</code></pre><p>Pretty much the same. What is one more <code>open(2)</code> after all. inotifywait(1) reports:</p>
<pre tabindex="0"><code>CLOSE_WRITE,CLOSE 4913
CLOSE_WRITE,CLOSE 5036
DELETE 5036
MOVED_FROM foo
CLOSE_WRITE,CLOSE foo
</code></pre><p>How about we make it work just a bit more:</p>
<pre tabindex="0"><code>$ n=4913
$ for i in {1..4096}; do n=$(($n+123)); touch files/$n; done
$ time vim files/foo +wq

real    0m0.041s
user    0m0.021s
sys     0m0.011s
</code></pre><p>Still far quicker than anybody would notice in already insane scenario. And
yet&hellip;</p>
<pre tabindex="0"><code>$ for i in {1..50000}; do n=$(($n+123)); touch files/$n; done
$ time vim files/foo +wq

real    0m0.134s
user    0m0.020s
sys     0m0.098s
</code></pre><p>Now, we&rsquo;re talking. I even saw the terminal flickering in order to draw the
window, before being able to finish with the <code>:wq</code> command. Testing with
anything more than that is way above any even remotely possible scenario.</p>
</details>
<p>Having thousands files in a single directory is something you never want in the
real world anyways. There are filesystems with a hard limit by design. While
modern filesystems don&rsquo;t, you will surely experience performance issues when
working with such a directory.</p>
<h2 id="y-tho">Y tho?</h2>
<p>Why am I telling you all this? Because I like digging deeper into such quirky
details. The next time you stumble upon something peculiar, remember: there
might just be an amusing or enlightening story waiting to be uncovered. Or
maybe not, but you&rsquo;ll learn something anyway.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Blocks of code into a C switch{}</title>
      <link>https://vld.bg/articles/blocks-in-c-switch/</link>
      <pubDate>Thu, 25 Jan 2024 23:28:32 +0200</pubDate>
      <guid>https://vld.bg/articles/blocks-in-c-switch/</guid>
      <description>&lt;p&gt;A while ago I was digging deep into a C++ project, chasing an obscure bug.
Neither the project in question nor the bug are important here. What&amp;rsquo;s
important is that I&amp;rsquo;ve stumbled upon a weird syntax, that seemed wrong. What&amp;rsquo;s
weird is that this block of code worked flawlessly, unlike some other parts of
the project.&lt;/p&gt;
&lt;p&gt;Turns out you can have blocks of code inside a switch statement spilling
between cases. Let me show you a simplified example:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>A while ago I was digging deep into a C++ project, chasing an obscure bug.
Neither the project in question nor the bug are important here. What&rsquo;s
important is that I&rsquo;ve stumbled upon a weird syntax, that seemed wrong. What&rsquo;s
weird is that this block of code worked flawlessly, unlike some other parts of
the project.</p>
<p>Turns out you can have blocks of code inside a switch statement spilling
between cases. Let me show you a simplified example:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">void</span> <span style="color:#447fcf">f</span>(<span style="color:#6ab825;font-weight:bold">int</span> a, <span style="color:#6ab825;font-weight:bold">int</span> b)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>	<span style="color:#6ab825;font-weight:bold">switch</span>(a) {
</span></span><span style="display:flex;"><span>	<span style="color:#6ab825;font-weight:bold">case</span> <span style="color:#3677a9">1</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#6ab825;font-weight:bold">if</span> (b &gt; <span style="color:#3677a9">0</span>) {
</span></span><span style="display:flex;"><span>	<span style="color:#6ab825;font-weight:bold">case</span> <span style="color:#3677a9">2</span>:
</span></span><span style="display:flex;"><span>			<span style="color:#447fcf">printf</span>(<span style="color:#ed9d13">&#34;a=%d b=%d</span><span style="color:#ed9d13">\n</span><span style="color:#ed9d13">&#34;</span>, a, b);
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h2 id="no-way">No way!</h2>
<p>Yep. That works. The if is taken into account only when <code>a</code> is 1, thus it
prints only if <code>b</code> is greater than 0. However, if <code>a</code> is 2, the function always
prints the values of <code>a</code> and <code>b</code>.</p>
<p>I&rsquo;m not really sure whether this behavior has been allowed on purpose. It was
more likely never thought of given that as stated in K&amp;R (page 53):</p>
<blockquote>
<p>[..] cases serve just as labels, after the code for one case is done,
execution falls through to the next unless you take explicit action to escape</p>
</blockquote>
<p>And really, they&rsquo;re just goto labels. In C <code>switch</code> is just a syntax sugar for
a <a href="https://en.wikipedia.org/wiki/Branch_table" target="_blank">branch table</a>
. No wonder that
the condition should always be an integer. The execution should jump to the
address of the given index (i.e. case condition) in the table. Once jumped, it
always moves on and falls through cases.</p>
<h2 id="y-tho">Y tho?</h2>
<p>When is it a good idea to do that, you ask? Never. Please, don&rsquo;t. I cannot
think of a single case (pun not intended) where this would make the code more
readable or less error-prone. Using this approach would be objectively worse in
every aspect. Besides, this doesn&rsquo;t even work in &ldquo;modern&rdquo; C-style languages,
where switch statements are not that simple, thankfully.</p>
<p>Why am I showing you this, then? Well, I find it hilarious and had a hard time
explaining it to a friend with words. It&rsquo;s nowhere trivial to find an example,
either. But now I have it written and will be able to explain that insanity
better while in a bar. I&rsquo;m fun at parties.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Type for a context value in Go</title>
      <link>https://vld.bg/articles/go-context-type/</link>
      <pubDate>Fri, 08 Dec 2023 19:16:54 +0200</pubDate>
      <guid>https://vld.bg/articles/go-context-type/</guid>
      <description>&lt;p&gt;Using context values in Go appears, at first sight, very trivial and easily
understood. There are pitfalls, though. For instance, what type to use for the
key?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ go doc context WithValue
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;package context // import &amp;#34;context&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;func WithValue(parent Context, key, val any) Context
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    WithValue returns a copy of parent in which the value associated with key is
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    val.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Use context Values only for request-scoped data that transits processes and
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    APIs, not for passing optional parameters to functions.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    The provided key must be comparable and should not be of type string or any
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    other built-in type to avoid collisions between packages using context.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Users of WithValue should define their own types for keys. To avoid
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    allocating when assigning to an interface{}, context keys often have
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    concrete type struct{}. Alternatively, exported context key variables&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    static type should be a pointer or interface.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This whole article exists because of this:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Using context values in Go appears, at first sight, very trivial and easily
understood. There are pitfalls, though. For instance, what type to use for the
key?</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-plain" data-lang="plain"><span style="display:flex;"><span>❯ go doc context WithValue
</span></span><span style="display:flex;"><span>package context // import &#34;context&#34;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>func WithValue(parent Context, key, val any) Context
</span></span><span style="display:flex;"><span>    WithValue returns a copy of parent in which the value associated with key is
</span></span><span style="display:flex;"><span>    val.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    Use context Values only for request-scoped data that transits processes and
</span></span><span style="display:flex;"><span>    APIs, not for passing optional parameters to functions.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    The provided key must be comparable and should not be of type string or any
</span></span><span style="display:flex;"><span>    other built-in type to avoid collisions between packages using context.
</span></span><span style="display:flex;"><span>    Users of WithValue should define their own types for keys. To avoid
</span></span><span style="display:flex;"><span>    allocating when assigning to an interface{}, context keys often have
</span></span><span style="display:flex;"><span>    concrete type struct{}. Alternatively, exported context key variables&#39;
</span></span><span style="display:flex;"><span>    static type should be a pointer or interface.
</span></span></code></pre></div><p>This whole article exists because of this:</p>
<blockquote>
<p>Users of WithValue should define their own types for keys.</p>
</blockquote>
<p>OK, but what would that type be? It should NOT be a string, but its underlying
type could be one. In fact, over the years, I&rsquo;ve used an internal string type
with a value equal to the full package name:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#999;font-style:italic">// ctxt is a dummy type for storing context values.
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic">//
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic">// For more information see the documentation of context.WithValue.
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span><span style="color:#6ab825;font-weight:bold">type</span> ctxt <span style="color:#6ab825;font-weight:bold">string</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">var</span> ctxkey ctxt = <span style="color:#ed9d13">&#34;github.com/org/project/pkg&#34;</span>
</span></span></code></pre></div><p>Now <code>&amp;ctxkey</code> is what we use as context key as suggested by the documentation
in order to avoid useless allocations. Often I would introduce public functions
to take or store their expected value, without dealing with keys, mostly for
testing. Suppose all this package needs a ctx type for is to store values of
type T:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#999;font-style:italic">// FromContext extracts a value of type T from the given context, returning its
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic">// zero value if not present.
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span><span style="color:#6ab825;font-weight:bold">func</span> <span style="color:#447fcf">FromContext</span>(ctx context.Context) T {
</span></span><span style="display:flex;"><span>	v, ok := ctx.<span style="color:#447fcf">Value</span>(&amp;ctxkey).(T)
</span></span><span style="display:flex;"><span>	<span style="color:#6ab825;font-weight:bold">if</span> !ok {
</span></span><span style="display:flex;"><span>		v = <span style="color:#447fcf">NewT</span>()
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#6ab825;font-weight:bold">return</span> v
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic">// WithValue returns a copy of parent with stored T inside.
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span><span style="color:#6ab825;font-weight:bold">func</span> <span style="color:#447fcf">WithValue</span>(parent context.Context, t T) context.Context {
</span></span><span style="display:flex;"><span>	<span style="color:#6ab825;font-weight:bold">return</span> context.<span style="color:#447fcf">WithValue</span>(parent, &amp;ctxkey, t)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p><code>pkg.FromContext(ctx)</code> takes a context and returns the <code>pkg.T</code> stored inside,
if any, for instance.</p>
<p>The point to store the full package name is merely to ease debugging and/or
tracing. This string is allocated only once, and we are using a pointer to it,
in order not to allocate once per assigning that key to <code>interface{}</code>. If we
want to get fanatical about that, the type of <code>ctxt</code> might be an empty struct:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#999;font-style:italic">// ctxkey is a dummy type for storing context values.
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic">//
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic">// For more information see the documentation of context.WithValue.
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span><span style="color:#6ab825;font-weight:bold">type</span> ctxkey <span style="color:#6ab825;font-weight:bold">struct</span>{}
</span></span></code></pre></div><p>Now we no longer need to use a pointer to ctxkey and just directly pass
<code>ctxkey{}</code> instead, because a value of <code>struct{}</code> never allocates as its size
is 0 anyways. When debugging you would still see the type of ctxkey, which (as
with any type) contains the full path to it.</p>
<p>I have no memory which tool/use-case didn&rsquo;t work well with <code>struct{}</code> so I&rsquo;ve
started using a string in the first place, but I&rsquo;m back to using <code>struct{}</code>
again these days.</p>
<h2 id="what-about-generics">What about generics?</h2>
<p>Yes, of course. Go has generics now for quite some time, why not sprinkling
some of it to solve that? We could. In fact, there is a proposal that is placed
on hold (at the moment of writing this) in order to give the community time to
play more with generics: <a href="https://github.com/golang/go/issues/49189" target="_blank">https://github.com/golang/go/issues/49189</a>
</p>
<p>If you have tens of packages storing stuff in contexts and are pretty sure that
this makes sense, might as well steal the proposed <code>Key[T]</code> from there.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Why does Vim really use hjkl?</title>
      <link>https://vld.bg/articles/hjkl/</link>
      <pubDate>Tue, 14 Nov 2023 16:09:17 +0200</pubDate>
      <guid>https://vld.bg/articles/hjkl/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is part of the talk &amp;ldquo;UNIX archeology&amp;rdquo; I gave at OpenFest 2023.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you, dear reader, are a vim user, you&amp;rsquo;ve probably seen this keyboard:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;ADM-3A keyboard&#34; loading=&#34;lazy&#34; src=&#34;https://vld.bg/img/posts/ADM-3A.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;It explains a lot about our beloved text-editor. CTRL is just where it has to
be in the first place, the Esc is so near and the &lt;code&gt;:&lt;/code&gt; symbol we use for
commands is not hidden behind a modifier like nowadays. But why the arrows?&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p>This is part of the talk &ldquo;UNIX archeology&rdquo; I gave at OpenFest 2023.</p>
</blockquote>
<p>If you, dear reader, are a vim user, you&rsquo;ve probably seen this keyboard:</p>
<p><img alt="ADM-3A keyboard" loading="lazy" src="/img/posts/ADM-3A.jpg"></p>
<p>It explains a lot about our beloved text-editor. CTRL is just where it has to
be in the first place, the Esc is so near and the <code>:</code> symbol we use for
commands is not hidden behind a modifier like nowadays. But why the arrows?</p>
<p>So, one might say: &ldquo;Well, because <a href="https://en.wikipedia.org/wiki/Bill_Joy" target="_blank">Bill
Joy</a>
 created
<a href="https://en.wikipedia.org/wiki/Vi_%28text_editor%29" target="_blank">vi</a>
 using this
<a href="https://en.wikipedia.org/wiki/ADM-3A" target="_blank">ADM-3A</a>
 terminal where the arrows just
happened to be located there&rdquo;. And that person would be absolutely right. But
why were they located there?</p>
<p>To be fair, if you look at other terminals from these days, where to put the
arrows was not really standardized. Not even the triangular shape, we&rsquo;re so
used with today. Most machines would put them in one line, but in different
order. For instance, some would go with <code>[↓] [↑] [←] [→]</code>. So far, the answer that they
just had to put them somewhere still holds.</p>
<h2 id="ascii">ASCII</h2>
<p>It was not random, though. You see, in
<a href="https://en.wikipedia.org/wiki/ASCII" target="_blank">ASCII</a>
 characters are not just put at
some point on random. There are fairly good decisions taken there that go
mostly unnoticed today as people no longer work directly with ones and zeroes
really. If you want to get the code for an upper-case letter you should add 64
to the position of that letter in the alphabet. If you want it to be
lower-case, add 96 instead. That&rsquo;s pretty clever, because it all boils down to
flipping a bit:</p>
<table>
  <thead>
      <tr>
          <th>ASCII Char</th>
          <th>H [←]</th>
          <th>J [↓]</th>
          <th>K [↑]</th>
          <th>L [→]</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Decimal</td>
          <td>72</td>
          <td>74</td>
          <td>75</td>
          <td>76</td>
      </tr>
      <tr>
          <td>Binary</td>
          <td>0<strong>1</strong>001000</td>
          <td>0<strong>1</strong>001010</td>
          <td>0<strong>1</strong>001011</td>
          <td>0<strong>1</strong>001100</td>
      </tr>
  </tbody>
</table>
<table>
  <thead>
      <tr>
          <th>ASCII Char</th>
          <th>h [←]</th>
          <th>j [↓]</th>
          <th>k [↑]</th>
          <th>l [→]</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Decimal</td>
          <td>104</td>
          <td>106</td>
          <td>107</td>
          <td>108</td>
      </tr>
      <tr>
          <td>Binary</td>
          <td>0<strong>11</strong>01000</td>
          <td>0<strong>11</strong>01010</td>
          <td>0<strong>11</strong>01011</td>
          <td>0<strong>11</strong>01100</td>
      </tr>
  </tbody>
</table>
<p>This first bit is always 0, as ASCII is a 7-bit character set. If the second
bit is up, we are dealing with a letter. If the third is up, then this letter
is a lower-case. It&rsquo;s that simple. But look what happens if we set both of
those 2nd and 3rd bits to zero:</p>
<table>
  <thead>
      <tr>
          <th>ASCII Char</th>
          <th>Backspace</th>
          <th>Linefeed</th>
          <th>Vertical Tab</th>
          <th>Formfeed</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Decimal</td>
          <td>8</td>
          <td>10</td>
          <td>11</td>
          <td>12</td>
      </tr>
      <tr>
          <td>Binary</td>
          <td>0<strong>00</strong>01000</td>
          <td>0<strong>00</strong>01010</td>
          <td>0<strong>00</strong>01011</td>
          <td>0<strong>00</strong>01100</td>
      </tr>
  </tbody>
</table>
<p>When pressing any of those four keys, the terminal has to take two decisions:</p>
<ul>
<li>If [Shift] is pressed, set the 3rd bit to 0</li>
<li>If [CTRL] is pressed, set the 2nd and 3rd bits to 0</li>
</ul>
<h2 id="but-wait-theres-more">But wait, there&rsquo;s more</h2>
<p>Legacy we still observe from this terminal doesn&rsquo;t end here, though.</p>
<h3 id="heading">~/</h3>
<p>Take a look at the top right button. Yep. That&rsquo;s why we are shortening the path
to user&rsquo;s home folder as <code>~/</code>.</p>
<h3 id="regular-expressions">Regular expressions</h3>
<p>If you ever wondered why <code>^</code> is the beginning of line or &ldquo;home&rdquo; position in
regular expression dialects, well&hellip; now you know :)</p>
]]></content:encoded>
    </item>
    <item>
      <title>Why do we have /usr?</title>
      <link>https://vld.bg/articles/usr/</link>
      <pubDate>Sun, 12 Nov 2023 15:13:10 +0200</pubDate>
      <guid>https://vld.bg/articles/usr/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is part of the talk &amp;ldquo;UNIX archeology&amp;rdquo; I gave at OpenFest 2023.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In modern contexts, /usr is essential for housing the majority of user
utilities and applications. This includes system-wide software and files like
standard programs, libraries, documentation, and much more. Unlike the root
filesystem, which contains the minimum necessary for booting and repairing the
system, /usr provides the bulk of the operating system&amp;rsquo;s functionality.&lt;/p&gt;
&lt;p&gt;However, have you ever thought why do we have seemingly duplicated with /
directories in there? For instance, there is /bin and /usr/bin, /lib and
/usr/lib, and lately we&amp;rsquo;ve started symlinking one to another. Surely, we
could&amp;rsquo;ve just avoided the need to have them both in the first place. But why
are they there?&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p>This is part of the talk &ldquo;UNIX archeology&rdquo; I gave at OpenFest 2023.</p>
</blockquote>
<p>In modern contexts, /usr is essential for housing the majority of user
utilities and applications. This includes system-wide software and files like
standard programs, libraries, documentation, and much more. Unlike the root
filesystem, which contains the minimum necessary for booting and repairing the
system, /usr provides the bulk of the operating system&rsquo;s functionality.</p>
<p>However, have you ever thought why do we have seemingly duplicated with /
directories in there? For instance, there is /bin and /usr/bin, /lib and
/usr/lib, and lately we&rsquo;ve started symlinking one to another. Surely, we
could&rsquo;ve just avoided the need to have them both in the first place. But why
are they there?</p>
<p>The <a href="https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard" target="_blank">Filesystem Hierarchy Standard
(FHS)</a>
 is a reference describing the
conventions used for the layout of Unix-like systems. Latest release defines its
<a href="https://refspecs.linuxfoundation.org/FHS_3.0/fhs-3.0.html#purpose18" target="_blank">purpose</a>
 as:</p>
<blockquote>
<p>/usr is the second major section of the filesystem. /usr is shareable,
read-only data. That means that /usr should be shareable between various
FHS-compliant hosts and must not be written to. Any information that is
host-specific or varies with time is stored elsewhere.</p>
<p>Large software packages must not use a direct subdirectory under the /usr
hierarchy.</p>
</blockquote>
<p>Actually, we only found out that we could mount /usr in read-only mode and even
re-use it between a bunch of machines, decades after /usr was part of Unix.</p>
<h2 id="no-space-left-on-device">no space left on device</h2>
<p>Unix was created on a <a href="https://en.wikipedia.org/wiki/PDP-7" target="_blank">PDP-7</a>
 machine in
1969 and later migrated (which included rewriting a bunch of things, but that&rsquo;s
a story for another time) to the much more powerful
<a href="https://en.wikipedia.org/wiki/PDP-11" target="_blank">PDP-11</a>
, which had one RK05 disk pack
(1.5MB):</p>
<p><img alt="RK05 disk pack" loading="lazy" src="/img/posts/rk05.jpg"></p>
<blockquote>
<p><a href="https://commons.wikimedia.org/wiki/User:ArnoldReinhold" target="_blank">Arnold Reinhold</a>
 | CC-BY-SA</p>
</blockquote>
<p>That was all. The entire / of Unix was on one of those drives, less than 1.5MB.
Eventually it grew, with its userbase, and they needed another one. It was
mounted into /usr in order to contain user home directories. There were
/usr/ken, /usr/dmr, /usr/bwk, etc. However, multiple users were writing useful
tools which they wanted to share and thus /usr/bin has been created. Eventually
man pages started getting into shape, fonts started being interesting, people
experimented with graphics and they all meant to be shared. The law was that
nothing on that drive should be crucial for the machine to boot. For instance,
you could not place the <code>mount</code> command in there, because something had to
mount /usr in the first place. This limitation no longer exists thanks to
initrd and initramfs.</p>
<p>Eventually, this drive grew bigger as well and they needed a 3rd one. It was
mounted into /home and all of the home directories have been moved there,
leaving /usr only for shareable files. That meant whole 3MB solely for the
operating system. Hell, yeah!</p>
<p>And then we just kinda gone with it. Once Unix was made (not quite) generally
available and the idea to split the OS into multiple drives was still legit.
This was no longer the case only decades later. Why going through a revolution for
that? Instead, people just made up rules and conventions on how to deal with /usr.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Why do we need hidden files?</title>
      <link>https://vld.bg/articles/hidden-files/</link>
      <pubDate>Fri, 10 Nov 2023 00:58:47 +0200</pubDate>
      <guid>https://vld.bg/articles/hidden-files/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is part of the talk &amp;ldquo;UNIX archeology&amp;rdquo; I gave at OpenFest 2023.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Hidden files are fairly popular these days, especially in our home folders. We
store configuration, cache, logs and whatnot in there. Here&amp;rsquo;s what&amp;rsquo;s going on
in the home folder on the machine I&amp;rsquo;m writting this right now:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;❯ find ~ -name &#39;.*&#39; -type d | wc -l
5768
❯ find ~ -name &#39;.*&#39; -type f | wc -l
30573
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But why?&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p>This is part of the talk &ldquo;UNIX archeology&rdquo; I gave at OpenFest 2023.</p>
</blockquote>
<p>Hidden files are fairly popular these days, especially in our home folders. We
store configuration, cache, logs and whatnot in there. Here&rsquo;s what&rsquo;s going on
in the home folder on the machine I&rsquo;m writting this right now:</p>
<pre><code>❯ find ~ -name '.*' -type d | wc -l
5768
❯ find ~ -name '.*' -type f | wc -l
30573
</code></pre>
<p>But why?</p>
<p>Suppose you&rsquo;re working on this new cool OS and receive it as a feature request:
&ldquo;We should introduce hidden files&rdquo;. How would you do it? Knowing that files
generally need attributes, why not create a new one for it? Exactly what
Microsoft has one for their <del>cool</del> OS:</p>
<p><img loading="lazy" src="/img/posts/windows_file_properties.png"></p>
<p>But that is not how we do that in Unix. Instead, soon after the beginning of
time, in Unix hidden files are those which name starts with a dot. Looks odd
when you think about it, trying to ignore the fact you&rsquo;re so used with them.
But why?</p>
<h2 id="its-not-a-bug-its-a-feature">It&rsquo;s not a bug, it&rsquo;s a feature!</h2>
<p>Rob Pike wrote an explanation on Google+. Even though Google killed
that service long ago, <a href="https://web.archive.org/web/20140803082229/https://plus.google.com/&#43;RobPikeTheHuman/posts/R58WgWwN9jp" target="_blank">The Wayback Machine has a record of
that</a>
:</p>
<blockquote>
<p>A lesson in shortcuts.</p>
<p>Long ago, as the design of the Unix file system was being worked out, the
entries . and .. appeared, to make navigation easier. I&rsquo;m not sure but I
believe .. went in during the Version 2 rewrite, when the file system became
hierarchical (it had a very different structure early on).  When one typed
ls, however, these files appeared, so either Ken or Dennis added a simple
test to the program. It was in assembler then, but the code in question was
equivalent to something like this:</p>
<p><code>if (name[0] == '.') continue;</code></p>
<p>This statement was a little shorter than what it should have been, which is</p>
<p><code>if (strcmp(name, &quot;.&quot;) == 0 || strcmp(name, &quot;..&quot;) == 0) continue;</code></p>
<p>but hey, it was easy.</p>
<p>Two things resulted.</p>
<p>First, a bad precedent was set. A lot of other lazy programmers introduced
bugs by making the same simplification. Actual files beginning with periods
are often skipped when they should be counted.</p>
<p>Second, and much worse, the idea of a &ldquo;hidden&rdquo; or &ldquo;dot&rdquo; file was created. As
a consequence, more lazy programmers started dropping files into everyone&rsquo;s
home directory. I don&rsquo;t have all that much stuff installed on the machine I&rsquo;m
using to type this, but my home directory has about a hundred dot files and I
don&rsquo;t even know what most of them are or whether they&rsquo;re still needed. Every
file name evaluation that goes through my home directory is slowed down by
this accumulated sludge.</p>
<p>I&rsquo;m pretty sure the concept of a hidden file was an unintended consequence.
It was certainly a mistake.</p>
<p>How many bugs and wasted CPU cycles and instances of human frustration (not
to mention bad design) have resulted from that one small shortcut about  40
years ago?</p>
<p>Keep that in mind next time you want to cut a corner in your code.</p>
<p>(For those who object that dot files serve a purpose, I don&rsquo;t dispute that
but counter that it&rsquo;s the files that serve the purpose, not the convention
for their names. They could just as easily be in $HOME/cfg or $HOME/lib,
which is what we did in Plan 9, which had no dot files. Lessons can be
learned.)</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>79 characters</title>
      <link>https://vld.bg/articles/79-characters/</link>
      <pubDate>Wed, 08 Nov 2023 22:35:33 +0200</pubDate>
      <guid>https://vld.bg/articles/79-characters/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is part of the talk &amp;ldquo;UNIX archeology&amp;rdquo; I gave at OpenFest 2023.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Have you ever thought why the 79 characters limit per line is so popular in
programming and pretty much nowhere else? Python with their notable PEP-0008,
the Linux kernel, PostgreSQL and the GNU project, just to name a few. Sounds
like an arbitrary one. But why?&lt;/p&gt;
&lt;h2 id=&#34;tty&#34;&gt;tty&lt;/h2&gt;
&lt;p&gt;People tend to believe that this is because terminals were able to print up to
80 symbols per line and this just got carried over. The most popular one being
VT100:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p>This is part of the talk &ldquo;UNIX archeology&rdquo; I gave at OpenFest 2023.</p>
</blockquote>
<p>Have you ever thought why the 79 characters limit per line is so popular in
programming and pretty much nowhere else? Python with their notable PEP-0008,
the Linux kernel, PostgreSQL and the GNU project, just to name a few. Sounds
like an arbitrary one. But why?</p>
<h2 id="tty">tty</h2>
<p>People tend to believe that this is because terminals were able to print up to
80 symbols per line and this just got carried over. The most popular one being
VT100:</p>
<p><img alt="DEC VT100" loading="lazy" src="/img/posts/DEC_VT100.jpg"></p>
<blockquote>
<p><a href="https://www.flickr.com/people/54568729@N00" target="_blank">Jason Scott</a>
 | CC BY 2.0</p>
</blockquote>
<p>To be fair, not all of them did, but VT100 is iconic enough to inspire such a
tradition. It was able to operate in two modes - 80 columns by 24 rows or 132
columns by 14 rows. So, we might as well agree with that and call it a night.
But why?</p>
<h2 id="ibm-80-column-punched-card">IBM 80-column punched card</h2>
<p>Okay, so seems like VT100 and some of its predecessor were not the first ones
sticking with 80 symbols. Here&rsquo;s the IBM 12-row/80-column punched card format
which came to dominate the industry:</p>
<p><img alt="IBM 12-row/80-column punched card" loading="lazy" src="/img/posts/ibm_punchcard.jpg"></p>
<blockquote>
<p><a href="https://www.flickr.com/people/93001633@N00" target="_blank">Pete Birkinshaw</a>
 | CC BY 2.0</p>
</blockquote>
<p>This makes sense. The EOL is an actual characters and this is how we&rsquo;ve ended
up with 79 characters limit, depending on whether you&rsquo;re counting the EOL as
one. So, this makes sense to be the initial reason for that limitation - the
most popular punched cards were limited to 80 symbols.
But why?</p>
<p>Initially, punched cards allowed far less characters per-line in order not to
tear the card with too many consecutive holes. In fact, way before that they
weren&rsquo;t used to store lines of text in the first place. The only thing that
never changed was the size of those cards.</p>
<h2 id="hollerith-tabulating-machine">Hollerith tabulating machine</h2>
<p><img alt="Hollerith tabulating machine" loading="lazy" src="/img/posts/HollerithMachine.CHM.jpg"></p>
<blockquote>
<p><a href="https://www.flickr.com/people/44124384537@N01" target="_blank">Adam Schuster</a>
 | CC BY 2.0</p>
</blockquote>
<p>The Hollerith Tabulating Machine, an ingenious invention of the late 19th
century, marked a pivotal moment in the history of data processing. Conceived
by Herman Hollerith, this revolutionary device was inspired by the challenges
of efficiently processing vast amounts of data from the 1890 U.S. Census. The
machine&rsquo;s core innovation lay in its use of punched cards, a concept borrowed
from the Jacquard loom, to store and sort data.</p>
<p>Each punched card represented a unique data point, with various patterns of
holes encoding specific information. When fed into the Hollerith machine, a
series of mechanical and electrical systems interpreted these holes, tabulating
and summarizing data with unprecedented speed and accuracy.</p>
<p>Yep, U.S. Census. Each card did NOT encode text, but the details for each
counted person. Here&rsquo;s what it looked like:
<img alt="Hollerith punched card" loading="lazy" src="/img/posts/hollerith_punched_card.png"></p>
<p>If you wonder what any of this means, early computers have a great article
about <a href="https://www.earlycomputers.com/cgi-bin/census1890_cards.cgi" target="_blank">1890 Census: The Meaning of the Hollerith Card
Codes</a>
. Some of
the entries here might not be approved by today&rsquo;s standards. So, the cards for
that machine were that big and every single machine dealing with punched cards,
kind of just went with it. But why were the cards for that machines so big?</p>
<p><img alt="US dollar bill from before 1920" loading="lazy" src="/img/posts/us1920.jpg"></p>
<p>U.S. dollar bills. See those boxes next to the machine? They were used to
transport bills which before 1920 were kind of huge. This way, you don&rsquo;t get to
manufacture new type of boxes and new type of paper cutters for those new
special cards.</p>
<p>So, the next time somebody asks you why they should abide to that 79-characters
per-line rule, you can tell them the old U.S. dollar bills are to blame. That&rsquo;s why!</p>
]]></content:encoded>
    </item>
    <item>
      <title>Open a pull request from command line</title>
      <link>https://vld.bg/articles/git-pull-request/</link>
      <pubDate>Mon, 23 Oct 2023 11:27:01 +0300</pubDate>
      <guid>https://vld.bg/articles/git-pull-request/</guid>
      <description>&lt;p&gt;When ready working on a &lt;a href=&#34;https://martinfowler.com/bliki/FeatureBranch.html&#34; target=&#34;_blank&#34;&gt;feature
branch&lt;/a&gt;
 in a project that
uses GitHub, GitLab or anything else like them, one generally do &lt;code&gt;git push -u origin &amp;lt;branch_name&amp;gt;&lt;/code&gt; and then goes to the web interface to open a pull
request. Pretty much all of these platforms provide the URL to go in order to
spare a few clicks. For instance:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ git push -u origin baba
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Enumerating objects: 1, done.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Counting objects: 100% (1/1), done.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Writing objects: 100% (1/1), 181 bytes | 181.00 KiB/s, done.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;remote:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;remote: Create a pull request for &amp;#39;baba&amp;#39; on GitHub by visiting:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;remote:      https://github.com/user/project_name/pull/new/baba
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;remote:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;To github.com:user/project_name.git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; * [new branch]      baba -&amp;gt; baba
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A few years ago &lt;a href=&#34;https://rstankov.com/&#34; target=&#34;_blank&#34;&gt;Rado Stankov&lt;/a&gt;
 wrote a great post about
a few git aliases and scripts he uses to automate things: &lt;a href=&#34;https://blog.rstankov.com/git-tricks/&#34; target=&#34;_blank&#34;&gt;Git
Tricks&lt;/a&gt;
. I took literally all of the
tricks he shows there in my &lt;a href=&#34;https://github.com/vladimiroff/dotfiles&#34; target=&#34;_blank&#34;&gt;dotfiles&lt;/a&gt;

and strongly suggest for you to do the same.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>When ready working on a <a href="https://martinfowler.com/bliki/FeatureBranch.html" target="_blank">feature
branch</a>
 in a project that
uses GitHub, GitLab or anything else like them, one generally do <code>git push -u origin &lt;branch_name&gt;</code> and then goes to the web interface to open a pull
request. Pretty much all of these platforms provide the URL to go in order to
spare a few clicks. For instance:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-plain" data-lang="plain"><span style="display:flex;"><span>❯ git push -u origin baba
</span></span><span style="display:flex;"><span>Enumerating objects: 1, done.
</span></span><span style="display:flex;"><span>Counting objects: 100% (1/1), done.
</span></span><span style="display:flex;"><span>Writing objects: 100% (1/1), 181 bytes | 181.00 KiB/s, done.
</span></span><span style="display:flex;"><span>Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
</span></span><span style="display:flex;"><span>remote:
</span></span><span style="display:flex;"><span>remote: Create a pull request for &#39;baba&#39; on GitHub by visiting:
</span></span><span style="display:flex;"><span>remote:      https://github.com/user/project_name/pull/new/baba
</span></span><span style="display:flex;"><span>remote:
</span></span><span style="display:flex;"><span>To github.com:user/project_name.git
</span></span><span style="display:flex;"><span> * [new branch]      baba -&gt; baba
</span></span></code></pre></div><p>A few years ago <a href="https://rstankov.com/" target="_blank">Rado Stankov</a>
 wrote a great post about
a few git aliases and scripts he uses to automate things: <a href="https://blog.rstankov.com/git-tricks/" target="_blank">Git
Tricks</a>
. I took literally all of the
tricks he shows there in my <a href="https://github.com/vladimiroff/dotfiles" target="_blank">dotfiles</a>

and strongly suggest for you to do the same.</p>
<p>One of tricks there is a <code>git-pull-request</code> scripts which allows automating
that clicking on the provided link with a <code>git pull-request</code> command. Over time
however, I&rsquo;ve started using GitLab and this trick no longer works for that, as
it assumes you&rsquo;re pushing into a GitHub repository. So, I had to modify that
script in order to be agnostic of the hosting you&rsquo;re using and simply open
whatever URL the upstream provdes on push (which to be fair, might be a bit
risky, if you&rsquo;re pushing to a shady git hosting, so use it with care):</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#cd2828;font-weight:bold">#!/bin/sh
</span></span></span><span style="display:flex;"><span><span style="color:#cd2828;font-weight:bold"></span><span style="color:#40ffff">current_branch</span>=<span style="color:#6ab825;font-weight:bold">$(</span>git rev-parse --abbrev-ref HEAD<span style="color:#6ab825;font-weight:bold">)</span>
</span></span><span style="display:flex;"><span>git push -v --set-upstream origin <span style="color:#ed9d13">&#34;</span><span style="color:#40ffff">$current_branch</span><span style="color:#ed9d13">&#34;</span> <span style="color:#40ffff">$2</span> 2&gt;&amp;<span style="color:#3677a9">1</span> | <span style="color:#6ab825;font-weight:bold">while</span> <span style="color:#40ffff">IFS</span>= <span style="color:#24909d">read</span> -r line
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">do</span>
</span></span><span style="display:flex;"><span>	<span style="color:#24909d">echo</span> <span style="color:#ed9d13">&#34;</span><span style="color:#40ffff">$line</span><span style="color:#ed9d13">&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#40ffff">url</span>=<span style="color:#6ab825;font-weight:bold">$(</span><span style="color:#24909d">echo</span> <span style="color:#ed9d13">&#34;</span><span style="color:#40ffff">$line</span><span style="color:#ed9d13">&#34;</span> | grep <span style="color:#ed9d13">&#34;remote:&#34;</span> | grep -Eo <span style="color:#ed9d13">&#39;(http|https)://[^ ]+&#39;</span><span style="color:#6ab825;font-weight:bold">)</span>
</span></span><span style="display:flex;"><span>	<span style="color:#6ab825;font-weight:bold">if</span> [ -n <span style="color:#ed9d13">&#34;</span><span style="color:#40ffff">$url</span><span style="color:#ed9d13">&#34;</span> ]
</span></span><span style="display:flex;"><span>	<span style="color:#6ab825;font-weight:bold">then</span>
</span></span><span style="display:flex;"><span>		xdg-open <span style="color:#ed9d13">&#34;</span><span style="color:#40ffff">$url</span><span style="color:#ed9d13">&#34;</span> &gt; /dev/null
</span></span><span style="display:flex;"><span>	<span style="color:#6ab825;font-weight:bold">fi</span>
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">done</span>
</span></span></code></pre></div><p>Note that as a linux user, I&rsquo;ve changed <code>open</code> to <code>xdg-open</code>. If you&rsquo;re using
macOS, might what to do <code>s/xdg-open/open/</code> over this.</p>
<p>If this is saved in a file named <code>git-pull-request</code> with execute permissions
(<code>+x</code>) at some of the directories listed in your <code>$PATH</code>, running <code>git pull-request</code> will push your current branch upstream and output exactly the
same as above, but also open the provided link in your default web browser
(presumably in a new tab).</p>
]]></content:encoded>
    </item>
    <item>
      <title>Simple Unix-like authorization with Go</title>
      <link>https://vld.bg/articles/go-unix-auth/</link>
      <pubDate>Sun, 03 Sep 2023 23:12:00 +0300</pubDate>
      <guid>https://vld.bg/articles/go-unix-auth/</guid>
      <description>&lt;p&gt;Modern complex projects often require sophisticated access-control
functionality, like Identity and Access Management
(&lt;a href=&#34;https://en.wikipedia.org/wiki/Identity_management&#34; target=&#34;_blank&#34;&gt;IAM&lt;/a&gt;
) systems. Sometimes,
however there are cases where simple solutions might just cut it. Let&amp;rsquo;s cover
one of these cases.&lt;/p&gt;
&lt;p&gt;Say we&amp;rsquo;re working on a system for publishing  articles, allowing discussion
below each article, with the following requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Moderators can edit all articles and comments&lt;/li&gt;
&lt;li&gt;Authors can create articles and edit only those created by themselves&lt;/li&gt;
&lt;li&gt;Users can read articles and post comments about them&lt;/li&gt;
&lt;li&gt;Any user-type can edit and delete their own profile&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We could define different user-levels as a bit-mask and store that alongside
user&amp;rsquo;s information (e.g. users table in the database):&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Modern complex projects often require sophisticated access-control
functionality, like Identity and Access Management
(<a href="https://en.wikipedia.org/wiki/Identity_management" target="_blank">IAM</a>
) systems. Sometimes,
however there are cases where simple solutions might just cut it. Let&rsquo;s cover
one of these cases.</p>
<p>Say we&rsquo;re working on a system for publishing  articles, allowing discussion
below each article, with the following requirements:</p>
<ul>
<li>Moderators can edit all articles and comments</li>
<li>Authors can create articles and edit only those created by themselves</li>
<li>Users can read articles and post comments about them</li>
<li>Any user-type can edit and delete their own profile</li>
</ul>
<p>We could define different user-levels as a bit-mask and store that alongside
user&rsquo;s information (e.g. users table in the database):</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">const</span> (
</span></span><span style="display:flex;"><span>	user = <span style="color:#3677a9">1</span> &lt;&lt; <span style="color:#6ab825;font-weight:bold">iota</span>    <span style="color:#999;font-style:italic">// 0001
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span>	author              <span style="color:#999;font-style:italic">// 0010
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span>	moderator           <span style="color:#999;font-style:italic">// 0100
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span>	self                <span style="color:#999;font-style:italic">// 1000
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span>)
</span></span></code></pre></div><p>Each of the actions listed above can now be expressed as a list of user types
allowed to perform them, by using the <a href="https://en.wikipedia.org/wiki/Bitwise_operation#OR" target="_blank">bitwise
OR</a>
 operator, omitting
actions allowed by everybody even without an account:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">const</span> (
</span></span><span style="display:flex;"><span>	CreateArticle = author
</span></span><span style="display:flex;"><span>	UpdateArticle = self | moderator
</span></span><span style="display:flex;"><span>	DeleteArticle = self | moderator
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	CreateComment = user | author | moderator
</span></span><span style="display:flex;"><span>	UpdateComment = moderator
</span></span><span style="display:flex;"><span>	DeleteComment = moderator
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	UpdateUser = self
</span></span><span style="display:flex;"><span>	DeleteUser = self
</span></span><span style="display:flex;"><span>)
</span></span></code></pre></div><p>Each action has only the bits of every user type set to 1. For instance
<code>CreateArticle</code> is 2 (0010), <code>UpdateArticle</code> is 12 (1100) and <code>CreateComment</code>
is 7 (0111). We could now create a function which determines whether given
action is allowed by simply checking if they share at least one bit set to 1,
for which we&rsquo;re going to utilize the <a href="https://en.wikipedia.org/wiki/Bitwise_operation#AND" target="_blank">bitwise
AND</a>
 operator.</p>
<p>self is a bit tricky here, because it must be populated differently per-entity.
So we should make sure that both users, articles and comments have ID:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">type</span> User <span style="color:#6ab825;font-weight:bold">struct</span> {
</span></span><span style="display:flex;"><span>	ID   ID
</span></span><span style="display:flex;"><span>	Role <span style="color:#6ab825;font-weight:bold">int</span>
</span></span><span style="display:flex;"><span>	Name <span style="color:#6ab825;font-weight:bold">string</span>
</span></span><span style="display:flex;"><span>	<span style="color:#999;font-style:italic">// ...
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">type</span> Article <span style="color:#6ab825;font-weight:bold">struct</span> {
</span></span><span style="display:flex;"><span>	ID     ID
</span></span><span style="display:flex;"><span>	Author ID
</span></span><span style="display:flex;"><span>	Name   <span style="color:#6ab825;font-weight:bold">string</span>
</span></span><span style="display:flex;"><span>	<span style="color:#999;font-style:italic">// ...
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">type</span> Comment <span style="color:#6ab825;font-weight:bold">struct</span> {
</span></span><span style="display:flex;"><span>	ID      ID
</span></span><span style="display:flex;"><span>	Author  ID
</span></span><span style="display:flex;"><span>	Article ID
</span></span><span style="display:flex;"><span>	<span style="color:#999;font-style:italic">// ...
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span>}
</span></span></code></pre></div><p>The <code>ID</code> type here can be anything comparable (e.g. int, string, UUID).
Now the function in question is painfully obvious:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">func</span> <span style="color:#447fcf">Allowed</span>(u User, action <span style="color:#6ab825;font-weight:bold">int</span>, target ID) <span style="color:#6ab825;font-weight:bold">bool</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#6ab825;font-weight:bold">if</span> user.ID == target {
</span></span><span style="display:flex;"><span>		u.Role |= self
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#6ab825;font-weight:bold">return</span> u.Role&amp;action != <span style="color:#3677a9">0</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p><code>target</code> is the ID of whatever is being acted upon or left with the zero value
for that type when not applicable (e.g. on any Create&hellip; action). In order to
check whether a user (u) can update given article (a) we call
<code>Allowed(u, UpdateArticle, a.Author)</code> and handle (e.g. return error) when the
result is false.</p>
<h2 id="however">However&hellip;</h2>
<p>You&rsquo;ve probably already figured out that this mimics the way Unix operating
systems encode filesystem access. I could think of a few pros to this approach:</p>
<ul>
<li>The check whether given action is allowed is trivial</li>
<li>Adding new user type is a single line of code. Each new user adds exactly one
bit to the mask, so until we go above 64, everything&rsquo;s fine</li>
<li>Permissions are obvious even to non-technical people</li>
<li>Same is applicable to pretty much any programming language I can think of</li>
</ul>
<p>However, this does not come without gotchas. Take that <code>self</code> which  is not
really a user type, but a made-up concept to allow everybody to edit <strong>some
of</strong> their own creations. We had to add it, because it&rsquo;s not a desired
capability for all entities. Comments for instance can NOT be edited, once
posted. Not only that, we had to add a new argument and logic to our little
pure function.</p>
<p>One could think of a few new requirements that would seem simple, yet require
more arguments, more checks and eventually a complete overhaul of this whole
idea. Technically speaking, even the Unix permissions turned out to
be not enough and modern Unix-like operating systems implement more complex
ACLs stored in the extended file attributes on top of it.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Friday deploys</title>
      <link>https://vld.bg/articles/friday-deploys/</link>
      <pubDate>Sun, 13 Aug 2023 01:17:48 +0300</pubDate>
      <guid>https://vld.bg/articles/friday-deploys/</guid>
      <description>&lt;p&gt;There are plenty of memes regarding deploying on Fridays and most of them seem
to be about how you should never do it. I find that strange. In fact I think
that every team developing a software product which ends up deployed on a
production server (trying to exclude on-premise software releases, work with me
here) should have a rule stating that there shall be no &lt;strong&gt;less&lt;/strong&gt; than two
Friday deploys per month.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>There are plenty of memes regarding deploying on Fridays and most of them seem
to be about how you should never do it. I find that strange. In fact I think
that every team developing a software product which ends up deployed on a
production server (trying to exclude on-premise software releases, work with me
here) should have a rule stating that there shall be no <strong>less</strong> than two
Friday deploys per month.</p>
<p>It sounds strange, right? Why <strong>two</strong>? Well, I&rsquo;ve started with a mandatory
Friday deploy each week. That turned out to be unpractical, though. You can&rsquo;t
always plan for changes to be ready for merging precisely on Fridays.</p>
<h2 id="checklist">Checklist</h2>
<p>On a more serious note. Let&rsquo;s go through what issues people tend to have with
deploying on Friday:</p>
<p>Most developers are already in weekend mood, they&rsquo;re not that focused thus it&rsquo;s
more likely to make a mistake while deploying. If developers are manually
deploying instead of a CI/CD, you have a problem to fix. Developers shouldn&rsquo;t
have to do anything more than pushing a button to initiate a deploy (preferably
the Enter button on a <code>git push</code> command).</p>
<p>There might be an ugly bug. Do you have tests, do you do code reviews or
probably have a QA team? If not, think about it. If yes, then you know that
there are still bugs that slip through. Just rollback.</p>
<p>But rolling back is hard, it takes time and people are already in that weekend
mood, remember? That means your rollback process is more than a push of a
button away. Go fix that.</p>
<p>Spotting bugs is harder on weekends. Why? Do you have people manually staring
at logs and graphs? Setup a proper monitoring system. I guess your product
doesn&rsquo;t close doors on weekends, so you need it anyways. If it does, though&hellip;
well&hellip; you got me.</p>
<p>But, but&hellip; many thing could go wrong you can&rsquo;t even imagine! Yes, that&rsquo;s most
probably right. What difference does it make if you deploy it on Wednesday?
It&rsquo;s still good to be <strong>reachable</strong> a few hours after deploy especially if there
are no people on-call 24/7, anyways.</p>
<h2 id="tldr">TL;DR</h2>
<p>Aim to deploy on Friday (preferably in the afternoon) every once in a while.
That will force you to set up solid deployment and monitoring procedures (and
habits in that matter) you really trust in.</p>
]]></content:encoded>
    </item>
    <item>
      <title>ttymouse_sgr</title>
      <link>https://vld.bg/articles/ttymouse-sgr/</link>
      <pubDate>Fri, 11 Aug 2023 23:52:50 +0200</pubDate>
      <guid>https://vld.bg/articles/ttymouse-sgr/</guid>
      <description>&lt;p&gt;Recently I bought myself a new &amp;ldquo;ultra-wide&amp;rdquo; monitor - LG 35WN75C. Quite nice if
you ask me. One of its greatest feature is that I can open 5-6 vertical splits
of code (I use vim btw) without sacrificing on readability. Soon, I&amp;rsquo;ve realized
that my mouse usage is increasing a lot. Apparently, scrolling through code and
selecting things, when out of the-zone™, is far more comfortable with the
mouse. How did I find that, you ask?&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Recently I bought myself a new &ldquo;ultra-wide&rdquo; monitor - LG 35WN75C. Quite nice if
you ask me. One of its greatest feature is that I can open 5-6 vertical splits
of code (I use vim btw) without sacrificing on readability. Soon, I&rsquo;ve realized
that my mouse usage is increasing a lot. Apparently, scrolling through code and
selecting things, when out of the-zone™, is far more comfortable with the
mouse. How did I find that, you ask?</p>
<p>Clicking on code in the fifth split left to write, actually got registered
as a click in the third one. Started to experiment and realized that it
registered properly on the 222nd column, but any other column after that got
also registered there. Weird. Something happens on column 223?</p>
<p>This is what my vim configuration looked like, when it comes to mouse support:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#999;font-style:italic">&#34; Mouse support</span>
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">set</span> mouse=a
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">if</span> !has(<span style="color:#ed9d13">&#39;nvim&#39;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">set</span> ttymouse=xterm2
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">endif</span>
</span></span></code></pre></div><p>No idea how did I ever got to that <code>ttymouse=xterm2</code>. Probably copied it from
somebody else&rsquo;s vimfiles. Anyways, apparently mouse support gets activated with
<code>set mouse=a</code>. Let&rsquo;s go into mouse&rsquo;s help and look for that magical number 223.
Open vim, call <code>:help mouse</code> and search for 223.</p>
<p>&hellip; and voilà! First result is precisely about that <code>xterm2</code> value of <code>ttymouse</code>:</p>
<blockquote>
<pre><code>     xterm        xterm-like mouse handling.  The mouse generates
                  &quot;&lt;Esc&gt;[Mscr&quot;, where &quot;scr&quot; is three bytes:
                          &quot;s&quot;  = button state
                          &quot;c&quot;  = column plus 33
                          &quot;r&quot;  = row plus 33
                  This only works up to 223 columns!  See &quot;dec&quot;,
                  &quot;urxvt&quot;, and &quot;sgr&quot; for solutions.
</code></pre>
</blockquote>
<p>So, I get to choose between dec, urxvt and sgr. After a bit of digging, it
looks like sgr is the most modern one, supported since 7.3.632. Here&rsquo;s the
patch if you&rsquo;re into this:
<a href="http://ftp.vim.org/pub/vim/patches/7.3/7.3.632" target="_blank">http://ftp.vim.org/pub/vim/patches/7.3/7.3.632</a>
</p>
<p>So, this is how my &ldquo;mouse setup&rdquo; looks like now:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#999;font-style:italic">&#34; Mouse support</span>
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">set</span> mouse=a
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">if</span> !has(<span style="color:#ed9d13">&#39;nvim&#39;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">if</span> has(<span style="color:#ed9d13">&#34;mouse_sgr&#34;</span>)
</span></span><span style="display:flex;"><span>        <span style="color:#6ab825;font-weight:bold">set</span> ttymouse=sgr
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">else</span>
</span></span><span style="display:flex;"><span>        <span style="color:#6ab825;font-weight:bold">set</span> ttymouse=xterm2
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">endif</span>
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">endif</span>
</span></span></code></pre></div><p>The mouse support is now working <del>great</del> well enough, considering we&rsquo;re
talking about a terminal application here.</p>
<h2 id="y-tho">Y tho?</h2>
<p>Why am I telling you all this? It&rsquo;s a clear example of how one can debug and fix
an issue in vim simply by browsing <code>:help</code>. Not to mention that I had two
different ways to arrive at the same help page. Notice that <code>if !has('nvim')</code>
there? I didn&rsquo;t even bother to check if the same reproduces in neovim (spoiler
alert: it does not). Instead of going through trial and error for that magical
number 223, I could&rsquo;ve just tried in neovim and then go directly into reading
<code>:help ttymouse</code>.</p>
<p>One can learn a lot about vim, simply by wandering in there. Apparently having
a good documentation helps your users. Modern software tend to overlook that. I
tend to overlook it into the software I write and maintain. The new way is
writing tutorials and endless <code>README.md</code> pages in the project&rsquo;s root. We might
want to reconsider this.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Hello world</title>
      <link>https://vld.bg/articles/hello-world/</link>
      <pubDate>Tue, 01 Aug 2023 23:45:14 +0300</pubDate>
      <guid>https://vld.bg/articles/hello-world/</guid>
      <description>&lt;p&gt;Looks like I&amp;rsquo;m trying to start blogging again. I&amp;rsquo;ve been thinking about it for
the past year or so. Eventually, I got it together, bought a domain, tried like
five different Hugo themes, did some nitpicking for quite some time and as it
often happens - completely abandoned that idea altogether.&lt;/p&gt;
&lt;p&gt;Later, pulled myself together, decided on a theme with solid card-like profile
homepage and zero content in there and deployed it. Then, abandoned the idea
again. A few months later pulled together again, bought another domain, started
drafting a bunch of posts for the past few months and got into the state &amp;ldquo;as
soon as I have 10 - we go live&amp;rdquo;.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Looks like I&rsquo;m trying to start blogging again. I&rsquo;ve been thinking about it for
the past year or so. Eventually, I got it together, bought a domain, tried like
five different Hugo themes, did some nitpicking for quite some time and as it
often happens - completely abandoned that idea altogether.</p>
<p>Later, pulled myself together, decided on a theme with solid card-like profile
homepage and zero content in there and deployed it. Then, abandoned the idea
again. A few months later pulled together again, bought another domain, started
drafting a bunch of posts for the past few months and got into the state &ldquo;as
soon as I have 10 - we go live&rdquo;.</p>
<p>That meant, getting to work on writing. So, naturally, I&rsquo;ve spend some days in
choosing a new theme, again and now I&rsquo;m pretty sure this should go live before
the end of 2023. If you&rsquo;re reading this, looks like I&rsquo;ve made it. The only
thing I&rsquo;ve been actually consistent enough is that I want to write on strictly
tech-related topics and there should be a <a href="/tips">tips/</a>
 section, because I
tend to forget a lot.</p>
]]></content:encoded>
    </item>
    <item>
      <title>~/.sqliterc</title>
      <link>https://vld.bg/tips/sqliterc/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://vld.bg/tips/sqliterc/</guid>
      <description>&lt;p&gt;TL;DR: &lt;code&gt;echo &#39;.mode box&#39; &amp;gt; ~/.sqliterc&lt;/code&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;SQLite is a great database (although often overlooked) with a bit of annoying CLI defaults.&lt;/p&gt;
&lt;p&gt;For instance:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;sqlite&amp;gt; select * from Album limit 10;
1|For Those About To Rock We Salute You|1
2|Balls to the Wall|2
3|Restless and Wild|2
4|Let There Be Rock|1
5|Big Ones|3
6|Jagged Little Pill|4
7|Facelift|5
8|Warner 25 Anos|6
9|Plays Metallica By Four Cellos|7
10|Audioslave|8
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Three columns, two of them are numbers, and yet things are hard to read. Write
&lt;code&gt;.mode box&lt;/code&gt; in your &lt;code&gt;~/.sqliterc&lt;/code&gt; and things change dramatically:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>TL;DR: <code>echo '.mode box' &gt; ~/.sqliterc</code></p>
<hr>
<p>SQLite is a great database (although often overlooked) with a bit of annoying CLI defaults.</p>
<p>For instance:</p>
<pre tabindex="0"><code>sqlite&gt; select * from Album limit 10;
1|For Those About To Rock We Salute You|1
2|Balls to the Wall|2
3|Restless and Wild|2
4|Let There Be Rock|1
5|Big Ones|3
6|Jagged Little Pill|4
7|Facelift|5
8|Warner 25 Anos|6
9|Plays Metallica By Four Cellos|7
10|Audioslave|8
</code></pre><p>Three columns, two of them are numbers, and yet things are hard to read. Write
<code>.mode box</code> in your <code>~/.sqliterc</code> and things change dramatically:</p>
<pre tabindex="0"><code>sqlite&gt; select * from Album limit 10;
┌─────────┬───────────────────────────────────────┬──────────┐
│ AlbumId │                 Title                 │ ArtistId │
├─────────┼───────────────────────────────────────┼──────────┤
│ 1       │ For Those About To Rock We Salute You │ 1        │
│ 2       │ Balls to the Wall                     │ 2        │
│ 3       │ Restless and Wild                     │ 2        │
│ 4       │ Let There Be Rock                     │ 1        │
│ 5       │ Big Ones                              │ 3        │
│ 6       │ Jagged Little Pill                    │ 4        │
│ 7       │ Facelift                              │ 5        │
│ 8       │ Warner 25 Anos                        │ 6        │
│ 9       │ Plays Metallica By Four Cellos        │ 7        │
│ 10      │ Audioslave                            │ 8        │
└─────────┴───────────────────────────────────────┴──────────┘
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>About me</title>
      <link>https://vld.bg/about/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://vld.bg/about/</guid>
      <description>&lt;p&gt;My name is Kiril Vladimirov, and I&amp;rsquo;m a software developer.&lt;/p&gt;
&lt;p&gt;My passion for technology ignited during my school years, when I wanted to
learn how to &amp;ldquo;create a website&amp;rdquo;™. A bunch of tutorials, web forums (remember
those?) and a few books later I began taking on freelance web development jobs.&lt;/p&gt;
&lt;p&gt;I pursued my higher education at the Faculty of Mathematics and Informatics
(FMI) at Sofia University St. Kliment Ohridski, specializing in Software
Engineering. Although I embarked on a master&amp;rsquo;s degree in Artificial
Intelligence, my interests shifted, leading me to focus more on practical
software development rather than completing my master&amp;rsquo;s studies.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>My name is Kiril Vladimirov, and I&rsquo;m a software developer.</p>
<p>My passion for technology ignited during my school years, when I wanted to
learn how to &ldquo;create a website&rdquo;™. A bunch of tutorials, web forums (remember
those?) and a few books later I began taking on freelance web development jobs.</p>
<p>I pursued my higher education at the Faculty of Mathematics and Informatics
(FMI) at Sofia University St. Kliment Ohridski, specializing in Software
Engineering. Although I embarked on a master&rsquo;s degree in Artificial
Intelligence, my interests shifted, leading me to focus more on practical
software development rather than completing my master&rsquo;s studies.</p>
<p>While in FMI teaching has also been a significant part of my journey, where I
taught <a href="https://fmi.golang.bg" target="_blank">&ldquo;Programming with Go&rdquo;</a>
 and <a href="https://fmi.py-bg.net" target="_blank">&ldquo;Programming with
Python&rdquo;</a>
. I also assisted in teaching courses &ldquo;Operating
Systems&rdquo; and &ldquo;Systems Programming&rdquo;.</p>
<p>In my professional career, I&rsquo;ve transitioned from web development to a more
focused role in backend systems. Currently, I&rsquo;m leading an infrastructure team
at <a href="https://siteground.com" target="_blank">SiteGround</a>
, developing the platform that underpins
most of our services.</p>
<p>The home page of this very site lists all the ways you could reach me. In case
you prefer mails, just hit me on kiril＠vld.bg.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Authorize SSH keys</title>
      <link>https://vld.bg/tips/ssh-keys/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://vld.bg/tips/ssh-keys/</guid>
      <description>&lt;p&gt;How often have you asked or have been asked to provide public SSH keys in order
to get authorized into given server or Git repository? I&amp;rsquo;ve heard horror
stories of people providing private keys, by mistake. GitHub and GitLab ease
this process greatly, but are not advertising it well enough.&lt;/p&gt;
&lt;p&gt;You can append &lt;code&gt;.keys&lt;/code&gt; to the URL of your profile in order to receive the
public keys you have on your account in a format to directly pipe it into
&lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt;:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>How often have you asked or have been asked to provide public SSH keys in order
to get authorized into given server or Git repository? I&rsquo;ve heard horror
stories of people providing private keys, by mistake. GitHub and GitLab ease
this process greatly, but are not advertising it well enough.</p>
<p>You can append <code>.keys</code> to the URL of your profile in order to receive the
public keys you have on your account in a format to directly pipe it into
<code>~/.ssh/authorized_keys</code>:</p>
<pre tabindex="0"><code>curl https://github.com/&lt;username&gt;.keys | tee -a ~/.ssh/authorized_keys
</code></pre><p>Same goes for any GitLab instance.</p>
]]></content:encoded>
    </item>
    <item>
      <title>find tricks</title>
      <link>https://vld.bg/tips/find/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://vld.bg/tips/find/</guid>
      <description>&lt;p&gt;Tasks I tend to forget how to perform with
&lt;a href=&#34;https://linux.die.net/man/1/find&#34; target=&#34;_blank&#34;&gt;find(1)&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id=&#34;delete-matched-files&#34;&gt;Delete matched files&lt;/h2&gt;
&lt;p&gt;The most trivial one: &lt;code&gt;find &amp;lt;path&amp;gt; [..] -delete&lt;/code&gt; (e.g. &lt;code&gt;find . -name foo -delete&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;However, depending on the OS &lt;code&gt;-delete&lt;/code&gt; might not be available. In that case,
see the next one.&lt;/p&gt;
&lt;h2 id=&#34;execute-command-with-matched-files&#34;&gt;Execute command with matched files&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;find &amp;lt;path&amp;gt; [..]  -exec &amp;lt;cmd&amp;gt; &#39;{}&#39; \;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;cmd&gt; is executed once for each matched file and the relative path to it is
replaces &lt;code&gt;&#39;{}&#39;&lt;/code&gt; and I always forget that &lt;code&gt;\;&lt;/code&gt;, which might be omitted depending
on a bunch of weird shell-isms
(e.g. &lt;code&gt;find . -name foo -exec rm -f &#39;{}&#39; \;&lt;/code&gt;).&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Tasks I tend to forget how to perform with
<a href="https://linux.die.net/man/1/find" target="_blank">find(1)</a>
.</p>
<h2 id="delete-matched-files">Delete matched files</h2>
<p>The most trivial one: <code>find &lt;path&gt; [..] -delete</code> (e.g. <code>find . -name foo -delete</code>).</p>
<p>However, depending on the OS <code>-delete</code> might not be available. In that case,
see the next one.</p>
<h2 id="execute-command-with-matched-files">Execute command with matched files</h2>
<pre><code>find &lt;path&gt; [..]  -exec &lt;cmd&gt; '{}' \;
</code></pre>
<p><cmd> is executed once for each matched file and the relative path to it is
replaces <code>'{}'</code> and I always forget that <code>\;</code>, which might be omitted depending
on a bunch of weird shell-isms
(e.g. <code>find . -name foo -exec rm -f '{}' \;</code>).</p>
<p>If you want to call <code>&lt;cmd&gt;</code> exactly once (with caveats) with all the matched
files passed as argument, add <code>+</code> at the end, but then <code>'{}'</code> should be right
at the end of the command just before the <code>+</code>:
<code>find . -type f -name 'foo*' -exec rm -f '{}' +</code></p>
<h2 id="match-files-by-modification-time">Match files by modification time</h2>
<pre><code>find &lt;path&gt; [..] -mtime [+-]n
</code></pre>
<ul>
<li>
<p>n means modified <strong>precisely</strong> n days ago. This matches all files modified
a week ago:<br><code>find . -mtime 7</code></p>
</li>
<li>
<p>+n means modified <strong>at least</strong> n days ago. This matches all files older than
a week:<br><code>find . -mtime +7</code></p>
</li>
<li>
<p>-n means modified <strong>within the last</strong> n days. This matches all files older than
a week:<br><code>find . -mtime -7</code></p>
</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Generate password</title>
      <link>https://vld.bg/tips/passwd/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://vld.bg/tips/passwd/</guid>
      <description>&lt;h2 id=&#34;pwgen-length-count&#34;&gt;pwgen [length] [count]&lt;/h2&gt;
&lt;p&gt;By default it generates a bunch of passwords in columns. However with args it
can be ustructed to generate one fairly long secret (64 characters):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pwgen 64 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It has fairly good number of ways to configure what and how exactly to
generate. The downside of this approach is that
&lt;a href=&#34;https://linux.die.net/man/1/pwgen&#34; target=&#34;_blank&#34;&gt;pwgen(1)&lt;/a&gt;
 is probably not installed by
default on your machine.&lt;/p&gt;
&lt;h2 id=&#34;devurandom&#34;&gt;/dev/urandom&lt;/h2&gt;
&lt;p&gt;Reading directly from /dev/urandom is the way to go on pretty much any UNIX
these days (or fallback to /dev/random, although both are the same except on
Linux) without having to install anything. The only question is how to make it
output plain-text.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h2 id="pwgen-length-count">pwgen [length] [count]</h2>
<p>By default it generates a bunch of passwords in columns. However with args it
can be ustructed to generate one fairly long secret (64 characters):</p>
<pre><code>pwgen 64 1
</code></pre>
<p>It has fairly good number of ways to configure what and how exactly to
generate. The downside of this approach is that
<a href="https://linux.die.net/man/1/pwgen" target="_blank">pwgen(1)</a>
 is probably not installed by
default on your machine.</p>
<h2 id="devurandom">/dev/urandom</h2>
<p>Reading directly from /dev/urandom is the way to go on pretty much any UNIX
these days (or fallback to /dev/random, although both are the same except on
Linux) without having to install anything. The only question is how to make it
output plain-text.</p>
<h3 id="base641httpslinuxdienetman1base64"><a href="https://linux.die.net/man/1/base64" target="_blank">base64(1)</a>
</h3>
<p>Arguably the easiest way if you don&rsquo;t care that the only possible &ldquo;special&rdquo;
characters besides letters and numbers are + and /:</p>
<pre><code>base64 /dev/urandom | head -c64
</code></pre>
<h3 id="tr1httpslinuxdienetman1tr"><a href="https://linux.die.net/man/1/tr" target="_blank">tr(1)</a>
</h3>
<p>If you need to define a strict alphabet to use for your secret:</p>
<pre><code>cat /dev/urandom | tr -dc 'a-zA-Z0-9_!@#$%^&amp;*()~+=-' | head -c64
</code></pre>
<h3 id="openssl1httpslinuxdienetman1openssl"><a href="https://linux.die.net/man/1/openssl" target="_blank">openssl(1)</a>
</h3>
<p>OpenSSL can also do the job with two possible outputs:</p>
<ul>
<li>
<p>hex: <code>openssl rand -hex 42</code></p>
</li>
<li>
<p>base64: <code>openssl rand -base64 42</code> (uses = paddings)</p>
</li>
</ul>
<p>The numeric argument is not characters, though.</p>
<h3 id="gpg1httpslinuxdienetman1gpg"><a href="https://linux.die.net/man/1/gpg" target="_blank">gpg(1)</a>
</h3>
<p>Because obviously GPG can do everything security related:</p>
<pre><code>gpg --gen-random --armor 1 42
</code></pre>
<p>First number is &ldquo;quality level&rdquo; which is&hellip; complicated as with anything
related to GPG anyways.</p>
]]></content:encoded>
    </item>
    <item>
      <title>git bisect</title>
      <link>https://vld.bg/tips/git-bisect/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://vld.bg/tips/git-bisect/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://git-scm.com/docs/git-bisect&#34; target=&#34;_blank&#34;&gt;git bisect&lt;/a&gt;
 provides easy to use binary
search approach in order to find a bad commit. This tip assumes you know how it
works is in general, but always forget what the commands are precisely.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Prepare a single command that tries to reproduce the bug (e.g. script,
test) &lt;strong&gt;off tree&lt;/strong&gt;. Bisect is about to start jumping around, so it can&amp;rsquo;t be
in the tree.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;git bisect start&lt;/code&gt;: begin the bisect session.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><a href="https://git-scm.com/docs/git-bisect" target="_blank">git bisect</a>
 provides easy to use binary
search approach in order to find a bad commit. This tip assumes you know how it
works is in general, but always forget what the commands are precisely.</p>
<ol>
<li>
<p>Prepare a single command that tries to reproduce the bug (e.g. script,
test) <strong>off tree</strong>. Bisect is about to start jumping around, so it can&rsquo;t be
in the tree.</p>
</li>
<li>
<p><code>git bisect start</code>: begin the bisect session.</p>
</li>
<li>
<p><code>git bisect bad</code>: mark current HEAD as a bad commit (i.e. the bug is
reproducible).</p>
</li>
<li>
<p><code>git bisect good &lt;commit-ref&gt;</code>: some known commit in the past, where the bug
does not exist.</p>
</li>
<li>
<p>You get dropped at a given commit. Try the command/test/script from step 1
and:</p>
<ul>
<li>if the bug exists: <code>git bisect bad</code></li>
<li>if the bug does NOT exist: <code>git bisect good</code></li>
</ul>
</li>
<li>
<p>Repeat until the initial bad commit is found.</p>
</li>
<li>
<p><code>git bisect reset</code>.</p>
</li>
</ol>
<h2 id="git-bisect-run">git bisect run</h2>
<p>Steps 5 and 6 can be automated with <code>git bisect run</code> if you can provide a
script that exits with status code 0 when the chosen revision is good and
something between 1 and 127 (except for 125) when the revision is bad.</p>
<p>The script should obviously be out of tree and executed with:</p>
<p><code>git bisect run &lt;script_name&gt; [&lt;arg&gt; ...]</code>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>nmap</title>
      <link>https://vld.bg/tips/nmap/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://vld.bg/tips/nmap/</guid>
      <description>&lt;h2 id=&#34;find-hosts-in-a-range&#34;&gt;Find hosts in a range&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;nmap -sn 1.2.3.0/24
&lt;/code&gt;&lt;/pre&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;HOST DISCOVERY:
-sL: List Scan - simply list targets to scan
-sn: Ping Scan - disable port scan
-Pn: Treat all hosts as online -- skip host discovery
-PS/PA/PU/PY[portlist]: TCP SYN, TCP ACK, UDP or SCTP discovery to given ports
-PE/PP/PM: ICMP echo, timestamp, and netmask request discovery probes
-PO[protocol list]: IP Protocol Ping
-n/-R: Never do DNS resolution/Always resolve [default: sometimes]
--dns-servers &amp;lt;serv1[,serv2],...&amp;gt;: Specify custom DNS servers
--system-dns: Use OS&amp;#39;s DNS resolver
--traceroute: Trace hop path to each host
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;port-scanning&#34;&gt;Port Scanning&lt;/h2&gt;
&lt;p&gt;Quick TCP SYN scanning (&lt;code&gt;-sS&lt;/code&gt;: requires root), skipping host discovery (&lt;code&gt;-Pn&lt;/code&gt;),
of most popular ports:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h2 id="find-hosts-in-a-range">Find hosts in a range</h2>
<pre><code>nmap -sn 1.2.3.0/24
</code></pre>
<pre tabindex="0"><code>HOST DISCOVERY:
-sL: List Scan - simply list targets to scan
-sn: Ping Scan - disable port scan
-Pn: Treat all hosts as online -- skip host discovery
-PS/PA/PU/PY[portlist]: TCP SYN, TCP ACK, UDP or SCTP discovery to given ports
-PE/PP/PM: ICMP echo, timestamp, and netmask request discovery probes
-PO[protocol list]: IP Protocol Ping
-n/-R: Never do DNS resolution/Always resolve [default: sometimes]
--dns-servers &lt;serv1[,serv2],...&gt;: Specify custom DNS servers
--system-dns: Use OS&#39;s DNS resolver
--traceroute: Trace hop path to each host
</code></pre><h2 id="port-scanning">Port Scanning</h2>
<p>Quick TCP SYN scanning (<code>-sS</code>: requires root), skipping host discovery (<code>-Pn</code>),
of most popular ports:</p>
<pre><code>nmap -sS -Pn 1.2.3.4
</code></pre>
<p>Port ranges can be given with <code>-p100-1000</code> (from :100 to :1000). All ports is
<code>-p-</code>. Single port is also accepted: <code>-p 22</code></p>
<p>UDP Scanning:</p>
<pre><code>nmap -sU -Pn 1.2.3.4
</code></pre>
<pre tabindex="0"><code>SCAN TECHNIQUES:
 -sS/sT/sA/sW/sM: TCP SYN/Connect()/ACK/Window/Maimon scans
 -sU: UDP Scan
 -sN/sF/sX: TCP Null, FIN, and Xmas scans
 --scanflags &lt;flags&gt;: Customize TCP scan flags
 -sI &lt;zombie host[:probeport]&gt;: Idle scan
 -sY/sZ: SCTP INIT/COOKIE-ECHO scans
 -sO: IP protocol scan
 -b &lt;FTP relay host&gt;: FTP bounce scan

PORT SPECIFICATION AND SCAN ORDER:
 -p &lt;port ranges&gt;: Only scan specified ports
   Ex: -p22; -p1-65535; -p U:53,111,137,T:21-25,80,139,8080,S:9
 --exclude-ports &lt;port ranges&gt;: Exclude the specified ports from scanning
 -F: Fast mode - Scan fewer ports than the default scan
 -r: Scan ports sequentially - don&#39;t randomize
 --top-ports &lt;number&gt;: Scan &lt;number&gt; most common ports
 --port-ratio &lt;ratio&gt;: Scan ports more common than &lt;ratio&gt;
</code></pre><h2 id="misc">Misc:</h2>
<ul>
<li>OS discover: <code>-O</code> (uppercase <code>o</code>, not a zero)</li>
<li>Application discovery: <code>-sV</code></li>
<li>Everything: <code>-A</code> (traceroute, app discovery, OS detecetion, port scanning&hellip;)</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>rsync</title>
      <link>https://vld.bg/tips/rsync/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://vld.bg/tips/rsync/</guid>
      <description>&lt;pre&gt;&lt;code&gt;rsync -arvzh [host:]/source/path/ [host:]/destination/path
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the trailing slash in source path: this avoids creating &lt;code&gt;[host:]/destination/path/path&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt;: archive (i.e. ensures that symlinks, attributes, permissions, owner, etc. are preserved)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt;: recursive&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt;: verbose (second &lt;code&gt;v&lt;/code&gt; gives what files are being skipped and some stats at the end)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-z&lt;/code&gt;: compress&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt;: human-readable format of numbers&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;--del | --delete&lt;/code&gt;: delete files on the destination that are not sent from
the source&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;--stats&lt;/code&gt;: file-transfer statistics at the end&lt;/p&gt;</description>
      <content:encoded><![CDATA[<pre><code>rsync -arvzh [host:]/source/path/ [host:]/destination/path
</code></pre>
<p>Note the trailing slash in source path: this avoids creating <code>[host:]/destination/path/path</code>.</p>
<ul>
<li><code>-a</code>: archive (i.e. ensures that symlinks, attributes, permissions, owner, etc. are preserved)</li>
<li><code>-r</code>: recursive</li>
<li><code>-v</code>: verbose (second <code>v</code> gives what files are being skipped and some stats at the end)</li>
<li><code>-z</code>: compress</li>
<li><code>-h</code>: human-readable format of numbers</li>
</ul>
<hr>
<ul>
<li>
<p><code>--del | --delete</code>: delete files on the destination that are not sent from
the source</p>
</li>
<li>
<p><code>--stats</code>: file-transfer statistics at the end</p>
</li>
<li>
<p><code>-m</code>: prune empty directories from file-list</p>
</li>
<li>
<p><code>-t</code>: preserve modification times</p>
</li>
</ul>
<hr>
<p>This is how I deploy changes of this site with rsync:</p>
<pre><code>rsync -arvzh --delete public/ vld.bg:www/vld.bg/public_html/ 
</code></pre>
]]></content:encoded>
    </item>
    <item>
      <title>SSH into an ancient machine</title>
      <link>https://vld.bg/tips/anctient-ssh/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://vld.bg/tips/anctient-ssh/</guid>
      <description>&lt;p&gt;TL;DR: &lt;code&gt;ssh -oHostKeyAlgorithms=+ssh-rsa -oRequiredRSASize=1024 &amp;lt;user&amp;gt;@&amp;lt;host&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Have you ever tried to SSH into an old machine, say a managed switch, UPS or
router from the previous decade only to get declined with the following error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Unable to negotiate with &amp;lt;host&amp;gt;: no matching host key type found.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Their offer: ssh-rsa,ssh-dss
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s frustrating, isn&amp;rsquo;t it?  OpenSSH implements all of the cryptographic
algorithms needed for compatibility with standards-compliant SSH
implementations, but since some of the older algorithms have been found to be
weak, not all of them are enabled by default. If you want to learn more about
it, definitely should read
&lt;a href=&#34;https://www.openssh.com/legacy.html&#34; target=&#34;_blank&#34;&gt;OpenSSH Legacy Options&lt;/a&gt;
.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>TL;DR: <code>ssh -oHostKeyAlgorithms=+ssh-rsa -oRequiredRSASize=1024 &lt;user&gt;@&lt;host&gt;</code></p>
<p>Have you ever tried to SSH into an old machine, say a managed switch, UPS or
router from the previous decade only to get declined with the following error:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-txt" data-lang="txt"><span style="display:flex;"><span>Unable to negotiate with &lt;host&gt;: no matching host key type found.
</span></span><span style="display:flex;"><span>Their offer: ssh-rsa,ssh-dss
</span></span></code></pre></div><p>It&rsquo;s frustrating, isn&rsquo;t it?  OpenSSH implements all of the cryptographic
algorithms needed for compatibility with standards-compliant SSH
implementations, but since some of the older algorithms have been found to be
weak, not all of them are enabled by default. If you want to learn more about
it, definitely should read
<a href="https://www.openssh.com/legacy.html" target="_blank">OpenSSH Legacy Options</a>
.</p>
<p>But this is a tip, so the short story is that you should use one of offered
algorithms by the server, say <code>-oHostKeyAlgorithms=+ssh-rsa</code>. When it comes to
ssh-rsa, however that won&rsquo;t be enough and you would be challenged with another
error:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-txt" data-lang="txt"><span style="display:flex;"><span>Bad server host key: Invalid key length
</span></span></code></pre></div><p>The crypto-policy that comes with modern distributions does not allow RSA key
sizes &lt; 2048 bit. Some SSH servers are configured with 1024-bit key sizes that
can lead to connection failures. <code>-oRequiredRSASize=1024</code> overrides that
default and Voilà.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Watch for file changes</title>
      <link>https://vld.bg/tips/inotify/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://vld.bg/tips/inotify/</guid>
      <description>&lt;p&gt;TL;DR: &lt;code&gt;inotifywait -m -e close_write -e delete -e move $(pwd)&lt;/code&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Example output under different conditions:&lt;/p&gt;
&lt;h3 id=&#34;touch-foo--echo---foo&#34;&gt;&lt;code&gt;touch foo&lt;/code&gt; &amp;amp;&amp;amp; &lt;code&gt;echo ... &amp;gt; foo&lt;/code&gt;&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;/path/to/watched/dir/ CLOSE_WRITE,CLOSE foo
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;mv-foo-bar&#34;&gt;&lt;code&gt;mv foo bar&lt;/code&gt;&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;/path/to/watched/dir/ MOVED_FROM foo
/path/to/watched/dir/ MOVED_TO bar
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;rm-bar&#34;&gt;&lt;code&gt;rm bar&lt;/code&gt;&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;/path/to/watched/dir/ DELETE bar
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;text-editors&#34;&gt;Text editors&lt;/h2&gt;
&lt;p&gt;This is where things get interesting&lt;/p&gt;
&lt;h3 id=&#34;vim&#34;&gt;vim&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;/path/to/watched/dir/ CLOSE_WRITE,CLOSE foo
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Boring, right? However, let&amp;rsquo;s do &lt;code&gt;:set backup&lt;/code&gt; and try again:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;/path/to/watched/dir/ CLOSE_WRITE,CLOSE 4913
/path/to/watched/dir/ DELETE 4913
/path/to/watched/dir/ MOVED_FROM foo
/path/to/watched/dir/ CLOSE_WRITE,CLOSE foo
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&#34;https://vld.bg/articles/4913_123/&#34;&gt;wut?&lt;/a&gt;
&lt;/p&gt;
&lt;h3 id=&#34;emacs&#34;&gt;emacs&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;/path/to/watched/dir/ CLOSE_WRITE,CLOSE foo
/path/to/watched/dir/ DELETE .#foo
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;.#foo&lt;/code&gt; is never created, yet deleted.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>TL;DR: <code>inotifywait -m -e close_write -e delete -e move $(pwd)</code></p>
<hr>
<p>Example output under different conditions:</p>
<h3 id="touch-foo--echo---foo"><code>touch foo</code> &amp;&amp; <code>echo ... &gt; foo</code></h3>
<pre tabindex="0"><code>/path/to/watched/dir/ CLOSE_WRITE,CLOSE foo
</code></pre><h3 id="mv-foo-bar"><code>mv foo bar</code></h3>
<pre tabindex="0"><code>/path/to/watched/dir/ MOVED_FROM foo
/path/to/watched/dir/ MOVED_TO bar
</code></pre><h3 id="rm-bar"><code>rm bar</code></h3>
<pre tabindex="0"><code>/path/to/watched/dir/ DELETE bar
</code></pre><h2 id="text-editors">Text editors</h2>
<p>This is where things get interesting</p>
<h3 id="vim">vim</h3>
<pre tabindex="0"><code>/path/to/watched/dir/ CLOSE_WRITE,CLOSE foo
</code></pre><p>Boring, right? However, let&rsquo;s do <code>:set backup</code> and try again:</p>
<pre tabindex="0"><code>/path/to/watched/dir/ CLOSE_WRITE,CLOSE 4913
/path/to/watched/dir/ DELETE 4913
/path/to/watched/dir/ MOVED_FROM foo
/path/to/watched/dir/ CLOSE_WRITE,CLOSE foo
</code></pre><p><a href="/articles/4913_123/">wut?</a>
</p>
<h3 id="emacs">emacs</h3>
<pre tabindex="0"><code>/path/to/watched/dir/ CLOSE_WRITE,CLOSE foo
/path/to/watched/dir/ DELETE .#foo
</code></pre><p><code>.#foo</code> is never created, yet deleted.</p>
<h3 id="vscode">vscode</h3>
<pre tabindex="0"><code>/path/to/watched/dir/ CLOSE_WRITE,CLOSE asdf
/path/to/watched/dir/ CLOSE_WRITE,CLOSE asdf
</code></pre><p>Not sure why it does it twice.</p>
]]></content:encoded>
    </item>
    <item>
      <title>What is my IP?</title>
      <link>https://vld.bg/tips/ip/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://vld.bg/tips/ip/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m using a page setup by Jason A. Donenfeld, which he uses to illustrate
&lt;a href=&#34;https://www.wireguard.com/quickstart/&#34; target=&#34;_blank&#34;&gt;setting up WireGuard&lt;/a&gt;
:
&lt;a href=&#34;https://zx2c4.com/ip&#34; target=&#34;_blank&#34;&gt;https://zx2c4.com/ip&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Even have it as an alias in my
&lt;a href=&#34;https://github.com/vladimiroff/dotfiles&#34; target=&#34;_blank&#34;&gt;dotfiles&lt;/a&gt;
:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;alias myip=&#39;curl -s https://zx2c4.com/ip | head -n1&#39;
&lt;/code&gt;&lt;/pre&gt;</description>
      <content:encoded><![CDATA[<p>I&rsquo;m using a page setup by Jason A. Donenfeld, which he uses to illustrate
<a href="https://www.wireguard.com/quickstart/" target="_blank">setting up WireGuard</a>
:
<a href="https://zx2c4.com/ip" target="_blank">https://zx2c4.com/ip</a>
</p>
<p>Even have it as an alias in my
<a href="https://github.com/vladimiroff/dotfiles" target="_blank">dotfiles</a>
:</p>
<pre><code>alias myip='curl -s https://zx2c4.com/ip | head -n1'
</code></pre>
]]></content:encoded>
    </item>
  </channel>
</rss>
