UTM icon indicating copy to clipboard operation
UTM copied to clipboard

CLI app discovery broken under certain circumstances (`utmctl` symlink)

Open lishaduck opened this issue 1 year ago • 8 comments

Describe the issue I don't have admin permissions, but I do have homebrew, so I installed UTM via homebrew with --appdir=~/Applications/. utmctl, however, errors as follows:

2024-08-15 20:28:29.203 utmctl[28511:15501686] Can't find app with file path /Applications/UTM.app
Error: Application not found.

I filed an issue over at Homebrew/homebrew-cask#182568, and I was directed to file an issue here.

Configuration

  • UTM Version: 4.5.3 (I'm about to upgrade, I'll update it if it fixes it)
  • macOS Version: 14.6.1
  • Mac Chip: M1

Crash log
n/a

Debug log
n/a

Upload VM
n/a


I haven't written Swift in ages, but I'm happy to try to fix it.

lishaduck avatar Aug 27 '24 15:08 lishaduck

How are you calling utmctl?

osy avatar Aug 27 '24 16:08 osy

How are you calling utmctl?

Oh, silly me 😅

$ utmctl list
2024-08-27 11:05:23.455 utmctl[37164:17429559] Can't find app with file path /Applications/UTM.app
Error: Application not found.

lishaduck avatar Aug 27 '24 16:08 lishaduck

Can you run ls -l $(which utmctl) and paste the output?

osy avatar Aug 27 '24 16:08 osy

lrwxr-xr-x  1 username  admin  58 Aug 27 11:00 /opt/homebrew/bin/utmctl -> /Users/username/Applications/UTM.app/Contents/MacOS/utmctl

lishaduck avatar Aug 27 '24 17:08 lishaduck

I've been playing around with this and it seems like it's actually not possible for a sandboxed CLI app to know what's its own real path is.

    /// Find the path to UTM.app
    private var utmAppUrl: URL {
        if let executableURL = Bundle.main.executableURL?.resolvingSymlinksInPath() {
            let utmURL = executableURL.deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent()
            if utmURL.lastPathComponent == "UTM.app" {
                return utmURL
            }
        }
        return URL(fileURLWithPath: "/Applications/UTM.app")
    }

This returns the default path if it cannot determine the correct path. However, when you symlink, Bundle.main.executableURL returns nil and Bundle.main.bundleURL returns nil as well. CommandLine.arguments.first returns a sandboxed path /Users/username/Library/Containers/com.utmapp.utmctl/Data/utmctl. I don't know any other way to do it.

The workaround is if you add /Users/username/Applications/UTM.app/Contents/MacOS to your PATH variable. For example by creating a new entry in /etc/paths.d/

osy avatar Aug 27 '24 18:08 osy

I've been playing around with this and it seems like it's actually not possible for a sandboxed CLI app to know what's its own real path is.

That's too bad, but thanks for investigating!

CommandLine.arguments.first returns a sandboxed path /Users/username/Library/Containers/com.utmapp.utmctl/Data/utmctl.

I never knew what ~/Library/Containers contained, and now I do, so at least I learned something :)

The workaround is if you add /Users/username/Applications/UTM.app/Contents/MacOS to your PATH variable.

Yeah, I figured that'd probably end up being the solution, though I'd rather it not be (my .zshrc file is complicated enough as it is, but at least I know where to fix it) I assumed that if vscode could do it, it couldn't be too hard, but vscode isn't sandboxed. For that matter, why is UTM sandboxed? It's not distributed via the mas.

lishaduck avatar Aug 27 '24 20:08 lishaduck

It is indeed distributed on MAS. And also because of the added security (if there's a QEMU bug, it won't automatically be able to rw your entire drive).

osy avatar Aug 27 '24 20:08 osy

It is indeed distributed on MAS.

Oh, yeah 🤦‍♂️

And also because of the added security (if there's a QEMU bug, it won't automatically be able to rw your entire drive).

I'm glad to hear that 😅

lishaduck avatar Aug 27 '24 21:08 lishaduck

Does sandboxing break _NSGetExecutablePath + realpath? If not, that could be added as a fallback if Bundle.main.executableURL fails.

I am too lazy to test that or make a PR, because just using a #!/bin/sh\nexec ~/Applications/UTM.app/Contents/MacOS/utmctl "$@" stub instead of a symlink works great.

percontation avatar Dec 20 '24 13:12 percontation

when they say a process in sandbox cannot know it's own path, does that mean that any other process, could tell you the path of the symbolically linked UTM app?

As I see homebrew in the top, is there a way to check the homebrew path using standard checks if a file exists if you know the path?

Lewiscowles1986 avatar Apr 07 '25 20:04 Lewiscowles1986