There isn’t a good way to handle all of these cases. You can separate 1 and 2 from 3 and 4 by configuring your launchd property list to pass the command a specific argument (--launchd is traditional but there’s no hard requirement).
Separating 1 and 2 is conceptually very hard. launchd is an on-demand system and there are multiple sources of demand. A scheduled start and IPC are simply different forms of demand. launchd maintain info about what demand first trigger a start (see launchctl blame) but that’s inherently racy. If launchd first notices the scheduled start and then, as its in the process of doing that start, it notices an IPC request, the start will be recorded as a scheduled start whereas in reality it’s both. It’s for this reason that the launchctl man page page says:
This subcommand is only intended for debugging and profiling use and
its output should not be relied upon in production scenarios.
Separating 3 and 4 is also hard. You’ll find that there are environment differences that you can use to tell them apart but there’s nothing explicit. This stuff can change at any time (and has done so in the past).
My preferred option here is to put all the real code into a framework and then have multiple executables, one for each context. The executables can then pass that context into the framework and then you know exactly what’s going on.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"