0

In my Linux Mint installation, I can directly execute a PE executable at the command line, and if it's a .NET/CLI executable, then it will automatically execute it with Mono, and otherwise, it will automatically execute it with Wine.

This works because binfmt is configured to run /usr/lib/binfmt-support/run-detectors for both CLI and Wine executables. This runs a series of detectors configured in /var/lib/binfmts to determine what type of PE executable it is and execute the appropriate command to run it.

In Manjaro, I have binfmt, but I don't have run-detectors. So I guess the first match in /proc/sys/fs/binfmt_misc wins, and I guess since I installed Wine before I installed Mono, that's the one that wins. That my supposition, anyway. The symptom is that whenever I execute an .exe file from the command line, it runs Wine, even if it's a .NET executable.

I can't find a package that seems to supply this run-detectors utility. Is there something like it in the standard or community repositories, or is there some other common way to set this up in the Arch world?

jasonwryan
  • 71,734
  • 34
  • 193
  • 226
P Daddy
  • 365
  • 3
  • 10

1 Answers1

1

I'm still hoping for a better answer from someone who knows a more idiomatic way to accomplish this, but in case there isn't one, for the benefit of future googlers, here's what I've done just to get it working for now:

From my Linux Mint installation, I copied /usr/lib/cli/binfmt-detector-cli. This file is provided by the Ubuntu mono-runtime package. I don't like grabbing an executable from another distro, but it should be a fairly simple executable that doesn't rely on much that might differ between different distros, as long as they're the same platform.

Alternatively, the source code can be retrieved and built:

git clone --filter=blob:none --depth 1 --no-checkout git://git.launchpad.net/ubuntu/+source/mono ubuntu-mono-binfmtdetect
cd ubuntu-mono-binfmtdetect
git sparse-checkout set debian/detector
git checkout
cd debian/detector
make
echo sudo install -o root -g root -m 0755 ./binfmt-detector-cli /usr/local/bin/

binfmt-detector-cli is a simple command that tests whether a file is a CLI executable, returning 0 or 1 on exit to indicate yes or no.

My Manjaro installation doesn't have a /usr/lib/cli directory, so I copied this file straight to /usr/bin/. Then a wrote a short shell script and saved it as /usr/bin/binfmt-mono-wine:

#!/bin/bash

if /usr/bin/binfmt-detector-cli "$1"; then
    mono "$@"
else
    wine "$@"
fi

Then I edited /usr/lib/binfmt.d/mono.conf, changing

:CLR:M::MZ::/usr/bin/mono:

to

:CLR:M::MZ::/usr/bin/binfmt-mono-wine:

and /usr/lib/binfmt.d/wine.conf, changing

:DOSWin:M::MZ::/usr/bin/wine:

to

:DOSWin:M::MZ::/usr/bin/binfmt-mono-wine:

You can see that both formats are now handled by the shell script, which uses the detector borrowed from Ubuntu to determine which command to launch.

Next, I had to deregister the old handlers and register the new ones. I found out that systemd has a service that will do that:

sudo /usr/lib/systemd/systemd-binfmt mono.conf
sudo /usr/lib/systemd/systemd-binfmt wine.conf

The last thing to do is to register a pacman hook so that future upgrades to mono and wine don't overwrite my changes to their binfmt configurations. I created /etc/pacman.d/hooks/binfmt-mono-wine.hook with these contents:

[Trigger]
Operation = Install
Operation = Upgrade
Type = File
Target = usr/lib/binfmt.d/mono.conf
Target = usr/lib/binfmt.d/wine.conf

[Action]
When = PostTransaction
Description = Updating binfmt configuration to use binfmt-mono-wine to differentiate between mono and wine executables
Exec = /usr/bin/xargs -I{} /usr/bin/sed -Ei 's_:/usr/bin/(mono|wine):_:/usr/bin/binfmt-mono-wine:_' /{}
NeedsTargets
Stephen Kitt
  • 411,918
  • 54
  • 1,065
  • 1,164
P Daddy
  • 365
  • 3
  • 10