diff options
Diffstat (limited to '')
-rw-r--r-- | content/20/index.md | 66 | ||||
-rw-r--r-- | content/21/index.md | 57 | ||||
-rw-r--r-- | content/21/places.png | bin | 0 -> 73620 bytes | |||
-rw-r--r-- | content/22/index.md | 52 | ||||
-rw-r--r-- | content/23/index.md | 140 |
5 files changed, 315 insertions, 0 deletions
diff --git a/content/20/index.md b/content/20/index.md new file mode 100644 index 0000000..fbc99c1 --- /dev/null +++ b/content/20/index.md @@ -0,0 +1,66 @@ ++++ +date = 2024-09-19T22:45:36+02:00 +title = "List mpv(1)'s watch_later entries with later(1)" + +[taxonomies] +tags = ["projects", "later(1)"] + +[extra] +related = [] ++++ + +If you are like me then you have a basically never-ending backlog of videos to +watch. Perhaps sometimes you even watch videos so long that they're basically +impossible to finish in one sitting. Or you have about an hour left on a video, +but you should really go to sleep. + +All of these require some way to remember the timestamp where you left off. I +use [`mpv(1)`](https://mpv.io/) to watch my videos and thankfully there is a +built-in way to do this. By default, hitting `Q` will quit the video and +remember the timestamp ([among other +settings](https://mpv.io/manual/stable/#resuming-playback)) for next time you +open the file. This works regardless of whether the video exists on your +filesystem or is streamed from a URL. + +After a while of using this you might amass more than a couple of unfinished +videos that `mpv(1)` knows about, but what it sadly does not provide is an easy +way to show you which videos those are... + +Whilst you can set +[`write-filename-in-watch-later-config`](https://mpv.io/manual/stable/#options-write-filename-in-watch-later-config) +and have `mpv(1)` save filenames and URLs in its watch later entries, quickly +finding them is another story. + +This is where a shared effort between my partner +[nortti](https://ahti.space/~nortti/) and me comes in: +[`later(1)`](https://git.oriole.systems/later/about/). It is a small Python +script that parses `mpv(1)`'s [watch +later](https://mpv.io/manual/stable/#watch-later) entries and displays them in a +human-readable and pretty manner: + +``` +albatross ~$ later +Sep 19 19:50 https://www.youtube.com/watch?v=VKGtMK4CGV4 # The 2 Hour Hunt for Light Arrows - OoT Randomizer +Sep 19 22:30 /home/wolf/Mall Grab - Understand feat. Brendan Yates.webm +``` + +From here it is easy to open up the video you want to continue watching: simply +paste the path or URL printed by `later(1)` into `mpv(1)`. + +You might notice that the YouTube video is commented with its title. This is not +information that `mpv(1)` saves, but `later(1)` can help here too. Using the +`-u` or `--update-titles` flag, it will extract video titles using +[`yt-dlp(1)`](https://github.com/yt-dlp/yt-dlp) and save them in its cache for +subsequent retrieval. This should work for any site that `yt-dlp(1)` itself +supports. + +If you have a Python available, setting up and using `later(1)` is trivial: +simply copy the script into a directory in your `$PATH` (and the manual into +`$MANPATH`) or use the `Makefile`: + +``` +$ PREFIX=~/.local make install +``` + +Do note that for `later(1)` to work correctly, the aforementioned +`write-filename-in-watch-later-config` setting needs to be set. diff --git a/content/21/index.md b/content/21/index.md new file mode 100644 index 0000000..384509f --- /dev/null +++ b/content/21/index.md @@ -0,0 +1,57 @@ ++++ +date = 2024-09-26T19:27:54+02:00 +title = "Pretty names for mount points in /etc/fstab" + +[taxonomies] +tags = ["TIL"] + +[extra] +related = [] ++++ + +The file manager I'm using on my Plasma 6 system, +[Dolphin](https://invent.kde.org/system/dolphin), has built-in support for +remote folders via the [KIO](https://invent.kde.org/frameworks/kio) framework. +Where before I was relying on [sshfs](https://github.com/libfuse/sshfs) mount +points in `/etc/fstab`, I decided to try out the Dolphin way and set up my +remote devices using its `sftp` backend. + +After a couple of days now I can say that this works beautifully... until you +want to access the remote device on something that does not interface with KIO. +This is especially important for me (and +[others](https://invent.kde.org/plasma/plasma-desktop/-/issues/71#note_640907)) +since I want to be able to browse networked filesystems via my terminal and have +the ability to directly open a terminal in that location through Dolphin, +something which is not possible with the KIO backend. + +So in the end I went back to mount points in `/etc/fstab`. One small problem +remained, however, and that was the way those mount points were displayed +within Dolphin. There seemed to be no way to customize a mount point's name or +icon, leading to an annoyingly long `/home/wolf/net/hosts/coleridge` entry in +the *Devices* section of Dolphin's places panel. + +I couldn't find any help in `fstab(5)`, and indeed I had never heard of a way +to give a mount point a "pretty name". However, after a bit of searching, I +found people offhandedly mentioning the `x-gvfs-name` option. Some more +searching revealed that nobody seems to care about documenting these features, +but I was finally able to find an authoritative source within [gvfs +itself](https://github.com/GNOME/gvfs/blob/989d746ed771fc5e5bf134677cf8d571170b262e/monitor/udisks2/what-is-shown.txt#L29-L35). + +Happily there's not only `x-gvfs-name` but also support for custom icons +through `x-gvfs-icon`. So, if you want your file manager to display a pretty +name and icon for one of your mount points, simply add the following to the +relevant entry in `/etc/fstab`: + +``` +x-gvfs-name=My%20Device,x-gvfs-icon=network-server +``` + +This should be possible at least on GNOME and KDE desktops. I imagine a bunch +of other environments and programs silently support this behaviour as well. + +{{ img(path="places.png", format="png", alt="A screenshot of Dolphin, KDE's +file manager, showing the user's home directory with the places panel on the +left side containing various categorized entries. The entries below the Devices +category read flood, demeter, coleridge, and OnePlus 12, each with its own +pretty name and relevant icon.", caption="Dolphin displaying pretty names and +icons in the *Devices* category") }} diff --git a/content/21/places.png b/content/21/places.png Binary files differnew file mode 100644 index 0000000..cfbd8e7 --- /dev/null +++ b/content/21/places.png diff --git a/content/22/index.md b/content/22/index.md new file mode 100644 index 0000000..c3ece23 --- /dev/null +++ b/content/22/index.md @@ -0,0 +1,52 @@ ++++ +date = 2024-09-28T18:23:12+02:00 +title = "MIME type subclassing and its consequences" + +[taxonomies] +tags = ["TIL"] + +[extra] +related = [] ++++ + +The freedesktop.org [shared MIME-info database +spec](https://specifications.freedesktop.org/shared-mime-info-spec/latest) says +the following in [section +2.11](https://specifications.freedesktop.org/shared-mime-info-spec/latest/ar01s02.html#subclassing): + +> A type is a subclass of another type if any instance of the first type is +> also an instance of the second. For example, all `image/svg+xml` files are +> also `application/xml`, `text/plain` and `application/octet-stream` files. +> Subclassing is about the format, rather than the category of the data (for +> example, there is no 'generic spreadsheet' class that all spreadsheets +> inherit from). +> +> Some subclass rules are implicit: +> - All `text/*` types are subclasses of `text/plain`. +> - All streamable types (ie, everything except the `inode/*` types) are subclasses of application/octet-stream. + +So far so good; this makes intuitive sense and seems sensible enough. There is +an interesting consequence of this rule when the MIME-info database is used by +desktop systems for file associations, however: **An application associated with +`application/octet-stream` will automatically be associated with all streamable +types as well.** + +This means that if you associate `application/octet-stream` with your text +editor, your desktop system will also suggest you open video and audio files +with that same text editor. This behaviour can be quite surprising, especially +if the association was added automatically when a file was opened through the +"Open with..." dialog. + +What is even more confusing if you don't happen to know the subclassing rule is +the fact that `~/.config/mimeapps.list` and applications interfacing with this +file will not even list the editor as associated with any audio or video files. +You might just skip over the entry it has for `application/octet-stream`, not +realizing its significance. Perhaps you even assume (understandably) that +`application/octet-stream` only specifies any file of "unknown" type. +User-facing documentation on desktop systems (if it even exists) does not +discuss this behaviour. + +Whilst looking into this I found an older KDE bug report with some [interesting +thoughts](https://bugs.kde.org/show_bug.cgi?id=425154#c2) on how to explain this +behaviour to the end user, but sadly as far as I have seen none of these have +made it into the system setting's file association dialog. diff --git a/content/23/index.md b/content/23/index.md new file mode 100644 index 0000000..442f383 --- /dev/null +++ b/content/23/index.md @@ -0,0 +1,140 @@ ++++ +date = 2024-10-02T18:42:07+02:00 +title = "musl and a curious Rust segfault" + +[taxonomies] +tags = ["bugs"] + +[extra] +related = [] ++++ + +About a week ago I noticed that [`fd(1)`](https://github.com/sharkdp/fd), a +Rust-based alternative to [`find(1)`](https://www.gnu.org/software/findutils/), +would suddenly segfault on my [musl](https://www.musl-libc.org/)-based server +system. Usually a segfault is nothing particularly special to my eyes, but this +one was different. Even just having `fd(1)` attempt to print its help text was +enough to trigger it, and when I attempted to debug it with +[`gdb(1)`](https://www.sourceware.org/gdb/), I saw the following: + +``` +(gdb) run +Starting program: /usr/bin/fd + +Program received signal SIGSEGV, Segmentation fault. +memcpy () at ../src_musl/src/string/x86_64/memcpy.s:18 +warning: 18 ../src_musl/src/string/x86_64/memcpy.s: No such file or directory +(gdb) bt +#0 memcpy () at ../src_musl/src/string/x86_64/memcpy.s:18 +#1 0x00007ffff7ab7177 in __copy_tls () at ../src_musl/src/env/__init_tls.c:66 +#2 0x00007ffff7ab730d in static_init_tls () at ../src_musl/src/env/__init_tls.c:149 +#3 0x00007ffff7aae89d in __init_libc () at ../src_musl/src/env/__libc_start_main.c:39 +#4 0x00007ffff7aae9c0 in __libc_start_main () at ../src_musl/src/env/__libc_start_main.c:80 +#5 0x00007ffff74107f6 in _start () +``` + +So... the segfault is in musl, not in `fd`!? + +I immediately checked whether other basic programs on the system worked. *They +did.* I checked when I last updated musl. *A couple of months ago, so that can't +be it.* I checked specifically whether another Rust-based program worked. *It +did.* + +`fd(1)` had been updated pretty recently, and I remembered it working correctly +about a month ago, so maybe something specific to `fd(1)`'s usage of Rust +triggered this segfault in musl? I wanted to make sure I could reproduce this in +a development environment, so I cloned the `fd(1)` repository, built a debug +release, and ran it... + +*It worked.* Huh!? + +I decided it was likely that [`portage`](https://wiki.gentoo.org/wiki/Portage), +Gentoo's package manager, was building the program differently, so I took care +to apply the same build flags to the development build. And what can I say: + +``` +error: failed to run custom build command for `crossbeam-utils v0.8.20` + +Caused by: + process didn't exit successfully: `fd/target/[...]/build-script-build` + (signal: 11, SIGSEGV: invalid memory reference) + +``` + +... it didn't even get to build the `fd` binary proper. A segfault again, too. +What on earth was going on? Why didn't this also happen in the `portage` build? + +Thankfully I now had a reproducer, so I did the only sensible thing and started +removing random build flags until I got `fd` to build again. This was our +culprit: + +``` +-Wl,-z,pack-relative-relocs +``` + +Already pretty out of my depth considering the fact that I couldn't fathom how +`fd(1)` got musl to segfault on `memcpy`, I now also found that a piece of the +puzzle required me to understand specific linker flags. *Oof.* + +Unsure what to do next I decided on a whim to compare the working and the +broken binary with `readelf(1)`. The most obvious difference was that the +working binary had its `.rela.dyn` +[relocation](https://en.wikipedia.org/wiki/Relocation_(computing)) section +populated with entries whilst the broken one was missing `.rela.dyn` but had +`.relr.dyn` instead. At a loss, I stopped and went to do something else. + +The story would probably have ended here had I not mentioned this conundrum to +[my partner](https://ahti.space/~nortti/) later in the day. We decided to have +another look at the binaries. After some discussion we determined that the +working binary was dynamically linked whilst the broken one wasn't. The other +working Rust-based program, [`rg(1)`](https://github.com/BurntSushi/ripgrep), +was also dynamically linked and had been built a while ago, so **at some point +`portage` must have stopped producing Rust executables that were dynamically +linked**. Finally some progress! + +At this point we need some background. Early on, Rust decided to use the +`x86_64-unknown-linux-musl` target to provide statically-linked binaries that +would run on a wide range of systems. Whilst support for dynamically linked +executables on musl systems was [added back in +2017](https://github.com/rust-lang/rust/pull/40113), the default behaviour was +never changed, so Gentoo has to make sure to disable static linking by passing +the `target-feature=-crt-static` flag. + +It does this in a system-wide fashion by setting an environment variable in +[`/etc/env.d`](https://wiki.gentoo.org/wiki//etc/env.d): + +``` +$ cat /etc/env.d/50rust-bin-1.80.1 +LDPATH="/usr/lib/rust/lib" +MANPATH="/usr/lib/rust/man" +CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_RUSTFLAGS="-C target-feature=-crt-static" +``` + +This setting should therefore be picked up by `portage` as well, but when I +examined its build environment it was simply not there. So finally we come to +the last piece of the puzzle: a [recent +change](https://gitweb.gentoo.org/repo/gentoo.git/commit/eclass/cargo.eclass?id=27d469a2114b4ad0b3e682854c50c806753eb472) +in how `RUSTFLAGS` are set within `portage`. Here's the important part: + +```bash +local -x CARGO_TARGET_"${TRIPLE}"_RUSTFLAGS="-C strip=none -C linker=${LD_A[0]}" +[[ ${#LD_A[@]} -gt 1 ]] && local CARGO_TARGET_"${TRIPLE}"_RUSTFLAGS+="$(printf -- ' -C link-arg=%s' "${LD_A[@]:1}")" +local CARGO_TARGET_"${TRIPLE}"_RUSTFLAGS+=" ${RUSTFLAGS}" +``` + +Quoth the `bash(1)` manual: + +> Local variables "shadow" variables with the same name declared at previous +> scopes. For instance, a local variable declared in a function hides a global +> variable of the same name: references and assignments refer to the local +> variable, leaving the global variable unmodified. + +When previously the `RUSTFLAGS` environment variable was only touched when +cross-compiling, it was now overridden. To confirm, I edited the file in +question to include the previous value, and both `fd(1)` and `rg(1)` worked +again. Success! + +This whole saga was also [reported](https://bugs.gentoo.org/940197) to the +Gentoo bug tracker and promptly fixed. A project for another day is figuring out +exactly how a change from static linking to dynamic linking causes segfaults +like this, because I sure would love to know the details. |