Linux setting of default application is a mess @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ :date: 2023-02-19 12:00 .. TODO: frontmatter Date: 2023-02-19 … so I made it `worse `_ by trying to solve it once again. This is a sad tale of a rather simple sysadmin's problem, distribution differences, standards and various ways of their abuse. The problem =========== We have a too-conventional setup with desktops shared by many users. This means we have many desktop environments and many different programs and now we need to make sure that even a new user with no defaults set in their profile can use the desktop at least somewhat. Thus, I need to make sure that the default default applications are reasonable and do e.g. open programs with user-friendly interface. And I want a reasonable way of specifying those defaults. Our environment is Debian based, but I found no reasonable method, so I wanted to check whether there is one in another distro. Oh boy that was a mistake, the state of affairs made me quite sad. The standards ============= There seem to be two major standards, both regarding mapping of MIME types to programs. The older standard is Mailcap. Somewhat specified in `RFC 1524 `_ (which was never declared to be a standard), it describes what applications should be used with what actions and under what conditions. One can use ``run-mailcap`` to use this way of opening files. This was in 1993. Then the "Linux desktop hurr durr people" (aka XDG or freedesktop.org) came along and saw that the Mailcap file is not enough INI. (And probably too useful, since the conditions could be arbitrary shell commands.) Comming from corporate environments, several standards (albeit quite short) have emerged: - `Desktop files with MimeType support directives `_ - |dfl-mime|_ .. |dfl-mime| replace:: Default application spec (``mimeapps.list``) .. _dfl-mime: https://specifications.freedesktop.org/mime-apps-spec/mime-apps-spec-latest.html .. What a lovely syntax this is. Ref: https://docutils.sourceforge.io/FAQ.html#is-nested-inline-markup-possible - `MIME type subclassing `_ (not to be confused or compared with subtypes from `original MIME type RFC 2026 `_) Also, the same group created ``xdg-utils``, supposedly reference implementation of the standard, containing the scripts like ``xdg-open`` and ``xdg-mime``. .. TODO: find the history of the stds to understand mimeinfo.cache, defaults.list and so on. The XDG standard has several deficiences, like not being able to specify broad rules like for ``video/*``. This leads to the ``mimeapps.list`` file being quite long and hard for administrators to actually generate it (e.g. if one would want to use, say, VLC for all video and audio files). With Mailcap, this really is quite similar, but on Debian a ``mailcap.order`` can be set up, which provides a simple way to prioritize some programs. More on that later. Also, Mailcap had support for different programs for viewing and creating the files. AFAIK that is not possible with XDG, since ``mimeapps.list`` has no way of distinguishing the use-cases. IMHO that is a shame, but apparently we have moved on. (XDG's deskop files usually describe human-readable program names and descriptions, which is a useful thing for desktop environments, so I guess that it is then simple to just embrace the XDG ecosystem.) Because the XDG standard is quite old, one would suppose that everyone uses ``mimeapps.list`` these days, and also that ``xdg-mime`` is bug-free. Well, neither of these is true. The abuse – what distributions do ================================= So I went to see how the popular desktop basic-user targetting distributions determine the default applications. I usually asked ``xdg-mime`` what program would be used for a PDF (or whatever got determined to have ``application/pdf`` type), and then ``strace``-ed it to determine which file was used to give the definitive answer. Since this is a bit of reverse engineering, I might have made some mistake and get wrong results. I just needed to skim through the distros, so I did not verify my findings. The command used: ``strace -ff -e %file,read,write -z xdg-mime query default application/pdf 2>&1 | less``. (Also, not everything would use ``xdg-mime``'s implementation to find the default app, but I need to go with something…) The following table shows my findings. I used the LiveCDs extensively (to quickly get a vanilla working setup), so I used the ISO filename as distro name (this also helps reproducing my results). Explanations follow the table. I was interested in both what file determines the defaults and how it got created. .. list-table:: Distribution default application mechanisms :header-rows: 1 * - Distro name (ISO) - Defaults file used - Package - Method of creation - Mailcap? - Other notes * - ``openSUSE-Leap-15.4-XFCE-Live-x86_64-Build31.98-Media.iso`` - ``xfce-mimeapps.list`` - ``xfce4-session-branding-openSUSE`` - Generated from ``/etc/xfce_defaults.conf`` by ``suse-update-mime-defaults`` - No - Actually usable for an admin, their config is short, readable and understandable. * - ``debian-live-11.6.0-amd64-xfce.iso`` - ``mimeinfo.cache`` - ``desktop-file-utils`` - ``update-desktop-database`` reads all the .desktop files and dumps the cache. - No - No way to prioritize, always uses lexicographically first? * - ``ubuntu-22.10-desktop-amd64.iso`` - ``defaults.list`` (``mimeinfo.cache`` as fallback) - ``desktop-file-utils`` - Unknown (shipped); ``update-desktop-database`` - Generated by ``update-mime`` - Several issues, see below * - ``Fedora-Workstation-Live-x86_64-37-1.7.iso`` - ``gnome-mimeapps.list`` (``mimeapps.list`` also present) - ``gnome-desktop3`` (``shared-mime-info``) - Unknown (shipped in both packages) - Minimal, delegating everything to ``xdg-open`` - Of course, interpretation of the files and the order is up to the implementation… ``xdg-mime``: The horror ------------------------ The spec for ``mimeapps.list`` describes the order for where to look for the file (I am omiting the environment variables and DE-specific lists for simplicity): #. ``~/.config/`` #. ``/etc/xdg/`` #. ``~/.local/share/applications/`` (deprecated) #. ``/usr/local/share/applications/`` and ``/usr/share/applications/`` This seems to be somewhat honored by ``xdg-mime``, as long as there is nothing else. When looking at what files the ``xdg-mime`` process (and children) opens, we see several other interesting paths: - ``~/.local/share/applnk/`` and ``/usr/share/applnk``. I have no idea where these come from. - ``~/.local/share/applications/defaults.list`` and ``mimeinfo.cache`` and the same files in ``/usr/share/applications/`` The `Debian wiki `_ tells us that the former is a historic name for ``mimeapps.list`` and the latter is just a mapping from MIME types to any desktop files which claim support for said type. Strangely, these two files seem to be checked at the same time, even though the ``mimeinfo.cache`` is much worse source for finding reasonable apps. (Also: at least on Debian ``mimeinfo.cache`` has wrong section header, but nobody seems to care.) - As the absolutely last resort, it seems to just read all the ``.desktop`` files and find any that could open the given MIME type. More bugs ````````` Apart from weird orders, there are several more bugs and issues: - While the shared-mime-info spec defines subclassing of MIME types, neither ``xdg-utils`` nor its dependencies care for the subclasses. - I am almost sure that the ``cut`` command in the ``check_mimeapps_list`` function (`source `_) prevents any fallbacks for a default app. Either the first desktop file in the list is present, or the whole ``mimeapps.list`` file is just skipped. - It seems that it sometimes does not check whether the given desktop file exists. Esp. on the live Ubuntu the best match for ``audio/flac`` is ``rhythmbox.desktop`` (from ``defaults.list``), but only ``org.gnome.Rhythmbox3.desktop`` exists. (``xdg-open`` can find the correct desktop file, I have no idea how.) Overall by skimming through the source code of ``xdg-mime`` I have the uneasy feeling of it being very inconsistent (e.g. sometimes a desktop file is parsed using ``awk``, and sometimes using ``grep`` and ``cut``). I did not dig too deep into the code nor the specifications, so I cannot say whether this is required by something or not. Does not feel like a dependable software though… Few notes on Mailcap -------------------- Unfortunately the venerable Mailcap feels quite irrelevant today, so I didn't even bother looking much into it yet. Weirdly though, various applications in Arch, Debian and Ubuntu do depend on or recommend Mailcap package, which seems that sometimes it might still be used, but AFAIK the XDG spec is prevalent, meaning the presence of mailcap might actually worsen the situation by having multiple configurations of default apps (except on Fedora, where it defers to ``xdg-open``). It should in theory be possible to create a default desktop app that would conversely defer handling of all known MIME types to Mailcap, but it is hard to make sure that the Mailcap file contains all programs. Since packages ship the desktop files, either the Mailcap generation would rely on the shipped file (which is not better than just using XDG), or it would require immense amount of work to keep everything in sync. Also, Mailcap itself does not in fact solve the administration problem of bulk-setting default apps. With vanilla Mailcap the order of directives in the file has to be maintained manually, and wildcard support for subtypes is prone to matching even unsupported files. This would create the opposite issue which would again lead to enumerating valid mime types for all apps. Debian has a mechanism for solving this: ``mailcap.order``. This file represents *MIME packages*, which take precedence in the resulting ``/etc/mailcap``. The package itself is just a file in ``/lib/mime/packages`` containing Mailcap entries. However, these files somewhat duplicate what desktop files already do (but probably didn't do when the mechanism emerged), and while they have more expressive power, only a handful of packages seem to provide these descriptions, rendering the idea useless. (Again, one could put immense work into creating all the packages, but at what cost. Also, this seems to be Debian-specific at the moment.) The solution – how and why I reimplemented openSUSE's solution ============================================================== At this point, I am quite sure that the only reasonable way forward is generating ``mimeapps.list`` from the desktop files. The easy way forward would just be using openSUSE's ``suse-update-mime-defaults``. Unfortunately it has several deficiencies: .. TODO: link the openSUSE sources - It cannot declare any kind of subset of types. Either an association is made for single (proper) MIME type, or for all supported types. This clashes with *web* browsers wanting to open everything including PDFs. This either means enumerating the allowed types, or elaborate setting of precedences in order to achieve the required order; neither option seems to be pleasant for an administrator. Similarly, one could end up with MPV displaying images, since it could do that. - It seems to be intended as internal tool for openSUSE, so I don't know how much would upstream be cooperative. - According to the recent changes, it needs to be updated for every DE supported. While it makes sense to tailor the application set, I don't think code changes are really needed. - It is mostly written in awk, which is unpleasant for me to read, so I want to avoid maintaining any forks of it. Also, I have no idea how and why it interacts with gio. My approach is to create a few simple utilities, which can be used as a building blocks for creating any required combinations: - The *defaulter* processes regex rules of default apps and produces a ``mimeapps.list`` file conforming to these rules and their order. - The *combiner* applies several ``mimeapps-list``-style files after one another, allowing reordering preferences and merging files. - The *expander* (not yet implemented) duplicates rules for subclasses, thus working around ``xdg-mime``'s failure to resolve superclasses when specific match is not found. - Possibly an *realizer* could be written, which would filter the list to contain only executable applications on current system, thus working around the failing-fallbacks bug. I chose to use regexes to achieve a format similar to the resulting ``mimeapps.list`` while being as general as possible. Particularly, wildcard subtypes, general rules and proper types are all quite simple (even though one needs to write e.g. ``image/.*`` instead of the canonical ``image/*``), and e.g. matching video codecs is possible with ``video/.*theora.*`` (albeit probably with some traps of matching wrong types). The scripts do not impose any kind of flow. You can pipeline them, ``make`` a workflow that creates DE-tailored lists, create a hook to update the defaults whenever a new package is installed, … I am not thinking of providing any such infrastructure first hand, though there might be some examples (possibly related to my use-case). Also, it is written in Python, which might provide better readability than awk. (Or it might not, given the shortcuts I sometimes use; you decide :-)) I do not aim for this to be a basic system tool, so I can afford to use non-POSIX interpreter. Enough talking, here is the repository: https://gitea.ledoian.cz/LEdoian/mimeapps-list-tools. Other things learned ==================== - Finding package sources for openSUSE is not straight forward. I have not found any kind of source download from Open Build Service, so I ended up with whatever ``zypper`` can do. There is ``zypper source-install``, which downloads the sources *somewhere* into ``/usr/src`` (the spec file ended up in different directory than the files for some reason). `This answer on Unix.SE `_ describes a way to get the tarball. (One apparently cannot query ``osc`` without having an account.) .. If the current state of "Linux on the desktop" is this horrible, I only want to run Linux on a server with keyboards, mice and monitors attached.