1

Before macosx 10.9 it was possible to detect if an executable was launched using launch services (finder, open, etc.) or directly invoked on the terminal by looking for the presence of a -psn_* argument in the program arguments.

This is no longer the case in 10.9. Is there a way of detecting that in 10.9 ? It seems I can look if cwd is / but that's not really foolproof.

Daniel Bünzli
  • 5,119
  • 20
  • 21
  • How would the excutable be invoked from terminal; using the `open` command? – Droppy Jul 29 '14 at 09:24
  • No that would use launch services. Like this: `/Applications/Myapp.app/Contents/MacOS/myexec`. – Daniel Bünzli Jul 29 '14 at 09:32
  • Indeed; just wanted to understand that you knew that. – Droppy Jul 29 '14 at 09:33
  • Other things that differ: parent process, inherited environment, stdout/stderr/stdin file descriptors (usually). You can try examining the current Apple Event (`[[NSAppleEventManager sharedAppleEventManager] currentAppleEvent]`) to see if something about it differs in a reliable way. Note, you may get an "oapp" or an "odoc" (or possibly "pdoc" or "ocon") depending. The relevant differences are more likely to be in the parameters or sender. – Ken Thomases Jul 29 '14 at 12:55
  • How about the parent process being `/sbin/launchd`? – Droppy Jul 29 '14 at 13:19
  • Does this help? http://stackoverflow.com/questions/22344967/detect-if-running-under-launchd/22345700#22345700 – Mark Setchell Jul 30 '14 at 14:46

1 Answers1

2

Trying to see of you are a child of launchd may actually be the sane way of doing but the solution I want needs to be conservative about the system calls you use.

Here are two different approaches. One is to to check whether one of the standard file descriptors is a tty (that won't work if they all redirected though). Sample code:

#include <unistd.h>

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
  if (isatty (STDIN_FILENO) || isatty (STDOUT_FILENO) || isatty(STDERR_FILENO))
  { printf ("tty launch\n"); fflush (stdout); }
  else
  { NSLog (@"Launch service"); }
}

the other one is too look if the environment variable TERM is unset or, for open launches, if the environment variable _ is /usr/bin/open):

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
  NSDictionary *env = [[NSProcessInfo processInfo] environment];
  NSLog(@"%@",env);
  NSString* term = [env objectForKey:@"TERM"];
  NSString* underscore = [env objectForKey:@"_"];

  if (!term || [underscore isEqualTo:@"/usr/bin/open"])
  { NSLog (@"Launch service"); }
  else
  { printf ("tty launch\n"); fflush (stdout); }
}
Daniel Bünzli
  • 5,119
  • 20
  • 21
  • Since it's easy to set `TERM` so it shows up in this context (`launchctl setenv TERM "myTerm"`) and someone may decide they want to, it might be better to check for the existence of the environment variable called `_` which is more likely to only be set by a shell (obviously, it could be set using the same method but there is less motivation to do so). This is quite an annoying problem because, as of 10.11 (and possibly earlier), the `isatty()` method no longer works (the standard file descriptors always seem to be ttys from the app's perspective). – Perry Mar 28 '16 at 20:44