9

I have a GUI macOS app that may also be launched from Terminal, with optional command line arguments.

When launched with arguments, I like to run the app in a "cmdline" mode where I do not display any UI but instead communicate via stdin + stdout only.

I can detect this cmdline mode like this:

BOOL cmdMode = NSProcessInfo.processInfo.arguments.count > 1;

(arg 0 is always the executable's path, so any more args would be manually passed args).

Now, here's the big question:

If the user invokes my app without arguments from Terminal (by invoking the app's executable in Contents/MacOS, i.e. not via the open cmd), I like to also go into the cmdline mode. How do I detect this?

Note: Older OS X versions did pass a "-psn ..." argument that, when not present, could be used to detect a launch from cmdline, but recent macOS versions seem to not pass this argument any more when launching apps from the Finder, so I cannot use that for detection any more.

Update

I realize that I can almost correctly solve this by checking for the presence of certain environment variables:

TERM and PWD are only set when launching the app from Terminal but not from Finder.

However, I also like to be able to tell the difference between being launched directly (executable in Contents/MacOS dir) vs. launched with the open command as I consider the open cmd being equivalent to opening the app via Finder or from another app via Launch Services.

In short, the question might also be: Detect whether an app was launched by Launch Services


For the record, here are the values from environ(). The ones marked with an asterisk are only present when invoked from Terminal.app but not when lanched from Finder:

    __CF_USER_TEXT_ENCODING=0x1F5:0x0:0x0
*   _=/Applications/Myapp.app/Contents/MacOS/Myapp
    Apple_PubSub_Socket_Render=/private/tmp/com.apple.launchd.laVQnD7IXl/Render
    HOME=/Users/username
*   LANG=en_US.UTF-8
*   LC_ALL=en_US.UTF-8
*   LC_CTYPE=UTF-8
    LOGNAME=username
    PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
*   PWD=/Users/username
    SHELL=/bin/bash
*   SHLVL=1
    SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.KeHv8KNuuk/Listeners
*   TERM_PROGRAM_VERSION=388.1.2
*   TERM_PROGRAM=Apple_Terminal
*   TERM_SESSION_ID=EF2C59E6-D661-45BE-B7EF-7A0E71158C8D
*   TERM=xterm-color
    TMPDIR=/var/folders/hm/ycnxcbwx8xl1v7008k8wnpjh0000gn/T/
    USER=username
    XPC_FLAGS=0x0
    XPC_SERVICE_NAME=0

There are, however, no envinment values that are unique to apps launched with Launch Services (such as when double clicked in Finder).

Thomas Tempelmann
  • 11,045
  • 8
  • 74
  • 149
  • 1
    This question is absolutely on-topic here, so my comment does not represent a complaint or an argument to close the question, but it's worth pointing out that there's a potential pool of experts over on [apple.se] that may be able to help. – David Thomas Oct 07 '18 at 11:01
  • 2
    I don't think I'll get an answer on A D because that's for users, while I'm asking a programmer's question. – Thomas Tempelmann Oct 07 '18 at 11:04
  • As noted I'm not voting to close/migrate because your question is on-topic here, but looking at AskDifferent they seem to have MacOS/iOS specific programming questions as well. But there is a very good chance that those answering programming questions there will also participate here. – David Thomas Oct 07 '18 at 11:06

1 Answers1

1

If you want to know what process has executed your program, you could use getppid() to get the parent process ID, then inspect that process to determine whether you were executed by an interactive shell process, or Finder, or launchctl, etc.

/sbin/launchd is PID 1 - if your process's parent PID is 1, you were executed by launchd.

Otherwise, you were executed by another process - probably an interactive shell, or as a subprocess of another process. You can use the KERN_PROCARGS syscall with sysctl() to get the process name by its PID.

You might also want to consider using isatty(STDIN) as well: interactive shells have a TTY, non-interactive shells and other processes won't.

dossy
  • 1,617
  • 16
  • 26