leah blogs

May 2020

02may2020 · The case of the mysterious --help directory

For quite some time—as my research will show, March 2016—, I have been annoyed by a directory named --help showing up in my home directory (and sometimes in others).

It’s just an empty, innocent directory with a weird name. Removed by a simple run of rmdir ./--help. Yet, it would turn up again. Sometimes soon, sometimes it took a few weeks.

I had no idea where it came from.

Obviously, a simple mkdir --help just print’s the mkdir help:

Usage: mkdir [OPTION]... DIRECTORY...
Create the DIRECTORY(ies), if they do not already exist.
...

I thought, maybe some program was called once with --help but didn’t understand it, yet stored it somewhere and would create it when run again. I suspected many things, especially applications I don’t use that often, like Gimp or Transmission. I grepped all dotfiles in $HOME for --help. To no avail.

I decided I had to track this down.

My first thought was to use fatrace, which logs all file accesses. But fatrace doesn’t register directory creation (the fanotify API does, I think).

I didn’t know what to do, and left the problem alone for some time. The --help directory kept reappearing.

Some time later, I read a book on eBPF, and decided I can log all mkdir(2) calls with it, globally. (I also think I tried this with SystemTap before, but I’m not sure anymore.)

I wrote a bpftrace script called mkdirsnoop, a variant of opensnoop. It would print all mkdir(2) calls and what program ran it, system wide.

I ran it a lot, but not consistently.

Yesterday, it finally triggered! I tweeted:

I’m really flipping the table.
For months, I’ve been trying to figure out what occasionally creates “–help” folders in my $HOME. I have no idea why it happens.
I wrote a bpftrace script to find the culprit.
Today it triggered.
It says, it’s mkdir(1).
(╯°□°)╯︵ ┻━┻

If it was mkdir(1), it must have been created by a script. Gimp and Transmission were acquitted of charge.

Julien Kirch proposed to put a different mkdir into my $PATH, which I think was a smart idea. I wrote this:

#!/bin/sh
printf '%s\n' "mkdir called from $$ at $(date)" >> /tmp/mkdirlog
pstree -sap $$ >> /tmp/mkdirlog
exec /usr/bin/mkdir "$@"

Very quickly, the script triggered, and I saw:

runit,1
  `-sh,30996 -c urxvt
      `-urxvt,30997
          `-zsh,30998
              `-zsh,31055
                  `-mkdir,31058 /home/leah/bin/mkdir --help
                      `-pstree,31060 -sap 31058

So it was actually zsh calling mkdir --help. (Or a zsh script.) But there was no directory --help. Because calling mkdir --help does not create a directory, instead printing the help.

Jannis Harder told me that the zsh completion for mkdir would run mkdir --help (to see if it’s the GNU variant), which I could verify.

But it didn’t explain the --help directory.

However, I had something to track down now.

Using my extrace, I would log all runs of mkdir with a --help argument, and at some point I found:

mkdir -p -- --help

Mysterious. I grepped my dotfiles again and found the unsuspicious function mkcd:

# mkcd -- mkdir and cd at once
mkcd() { mkdir -p -- "$1" && cd -- "$1" }

This is a helper function I use a lot. But I don’t call it with --help of course, and then wonder for 4 years why I do that.

Well I don’t. But zsh does, because I also had:

compdef mkcd=mkdir

This was a quick shortcut to complete mkdir’s arguments (only directories) also for mkcd. I added it in 2013. Even before I added the -p flag in 2016.

Quickly, I verified that mkcd <TAB> would create a --help directory. But only if the completion wasn’t loaded already, e.g. when I didn’t run mkdir <TAB> before. This explains why the directory only appeared sporadically.

I quickly rewrote the completion:

_mkcd() { _path_files -/ }
compdef _mkcd mkcd

And another mystery of my setup has been solved. Case closed.

NP: Pearl Jam—Take The Long Way

Copyright © 2004–2022