How to know a specific launchd .plist file location?
Asked Answered
R

8

37

Is it possible to know the .plist file location which is loaded by the launchctl command?

The label name is listed with launchctl list and its contents can be viewed by launchctl list LABEL, but I cannot find the .plist file location.

I know it will be located in /Library/LaunchAgent or ~/Library/LaunchAgent or somewhere, but I don't want to search around paths for all jobs listed by the launchctl command.

Roily answered 29/8, 2013 at 5:9 Comment(1)
Thank you trojanfoe, i didn't know about the site!Roily
T
24

As of macOS 10.12.6 (not sure about earlier versions) it is possible to invoke: launchctl dumpstate and you will get a wealth of information about all running processes

Look for <LABEL> = { as the first line of info pertaining to that job

Here's a one liner to get all the active daemons and their plist paths:

grep -B 1 -A 4 "active count = 1$" <<< "$(launchctl dumpstate)"

Update: Since 10.12 macOS has added other values so the grep -A n has been increased to 4 lines

Tanney answered 20/9, 2017 at 5:25 Comment(3)
On my machine anyway this doesn't work. It only gives a partial dump then just stops with no error message or anything in the middle of a random service after exactly 20mb of dataBronchus
@None: the followup question you asked launchctl dumpstate won't give full dumpShawn
@JoelBruner: launchctl dumpstate is very useful; note it's an undocumented subcommand of launchctl, not even listed under "LEGACY SUBCOMMANDS"Shawn
D
16

This issue comes up a lot and unfortunately locate and mdfind both don't show results from the appropriate directories on my system. I put the following function in my .bashrc so I could quickly search the directories where launchctl looks for plist files.

launchctlFind () {
    LaunchctlPATHS=( \
        ~/Library/LaunchAgents \
        /Library/LaunchAgents \
        /Library/LaunchDaemons \
        /System/Library/LaunchAgents \
        /System/Library/LaunchDaemons \
    )

    for curPATH in "${LaunchctlPATHS[@]}"
    do
        grep -r "$curPATH" -e "$1"
    done
    return 0;
}

Note that this only checks in the directories where launchctl looks for files at boot-up and login. It may not find everything because jobs can be manually loaded by the user and/or other processes.

UPDATE: For those running macOS 10.12.6 or higher I would recommend using Joel Bruner's solution.

Dormitory answered 6/3, 2015 at 21:15 Comment(1)
It's better to change "grep -r " to "grep -R" to let the grep command follow symlinks.Renettarenew
S
7

This question might have has no answer! It seems that not everything in launchctl list will have a plist file at all.

As mentioned, launchctl dumpstate will give you tons of info on things including the plist path, if it exists.

You can run this command to approximately see a list of everything running and its plist path.

launchctl dumpstate | grep -A4 " = {" | grep -B 3 -A 3 -E "active count = [1-9]"

(Though this also seems to include other programs running that aren't daemons managed by launchd?)

The agents/daemons will have a path field underneath their identifier. Usually, the paths point to a plist file in the standard 5 locations described by Reed's answer. However, it doesn't have to be. For example Steam loads a launchctl service from a nonstandard location.

➜ launchctl dumpstate | grep -A4 " = {" | grep -B 3 -A 3 -E "active count = [1-9]"  | grep valve
com.valvesoftware.steam.ipctool = {
    path = /Users/chris/Library/Application Support/Steam/com.valvesoftware.steam.ipctool.plist

Fortunately that practice isn't too popular so searching the standard locations is usually sufficient.

But that's not the trickiest thing. I don't know the specifics but it appears that launchctl services can be loaded without a corresponding plist file at all. For example, this is what dumpstate says for the 1Password helper daemon.

➜ launchctl dumpstate | grep -A4 " = {" | grep -B 3 -A 3 -E "active count = [1-9]"  | grep -A4 "onepassword7-helper = {"
2BUA8C4S2C.com.agilebits.onepassword7-helper = {
    active count = 5
    path = (submitted by smd.1154)
    state = running

I don't know what "submitted by smd" really means, but it boils down to even if I see a helper in launchctl list there might not be any plist on the filesystem. Because of this I don't know how to launchctl unload this service because unload requires a plist path! And since this process is managed by launchd, even if I pkill -9 onepassword7-helper, launchd sees that the process stopped and starts it right back up again.

(fortunately for this particular 1Password example, if you hold ^ and when clicking Quit 1Password, a special "Quite 1Password Completely" option will appear)

Sharynshashlik answered 3/11, 2019 at 4:11 Comment(2)
Funny side note, but I've been using grep for years and wasn't aware of the -B and -A flags until I just read this post. This is tremendously useful. Thanks!Satang
@Satang looking back on it now, my use of -B 3 -A 3 should really just be -C 3, since that's the same thing :-DSharynshashlik
T
6

In recent versions of macOS you can use the launchctl print command. You have to know which domain it's running under, e.g. system or gui/<uid>. There are a few other domains you can find in the man page, but so far I have only seen services running under these two. Examples:

% launchctl print gui/$(id -u)/com.apple.cloudphotod  | grep path
    path = /System/Library/LaunchAgents/com.apple.cloudphotod.plist

 % launchctl print system/com.openssh.sshd | grep path 
    path = /System/Library/LaunchDaemons/ssh.plist
    stderr path = /dev/null

I believe this command was implemented in High Sierra or thereabouts.

Thompson answered 22/12, 2020 at 15:19 Comment(0)
C
4

The process name used in launchctl list is declared in a plist. While the plist should be at the location mentioned above, they can be almost anywhere.

I found the plist i was looking for with' locate. I was looking for org.postgresql.postgres locate *.plist | grep org.postgresql.postgres narrowed it down to 4 files

Cherilyncherilynn answered 11/1, 2014 at 2:0 Comment(0)
L
3

Here is the command to list all loaded .plist files and their corresponding files:

find /System/Library/Launch* /Library/Launch* ~/Library/Launch* -name '*.plist' -exec sh -c '/usr/libexec/PlistBuddy -c "Print Label" {} && echo {}' ';' | grep -wf <(launchctl list | grep -o "\S\+\..*$") -A1 | strings

or another version:

find /System/Library/Launch* /Library/Launch* ~/Library/Launch* -name '*.plist' -exec /usr/libexec/PlistBuddy -c "Print Label" {} ';' -print | grep -wf <(launchctl list | grep -o "\S\+\..*$") -A1 | strings

Explanation:

  • find all .plist files in the following locations: /System/Library/Launch* /Library/Launch* ~/Library/Launch*
  • Use PlistBuddy command to print Label of all found .plist files.
  • Use -print parameter of find to print the path to that file.
  • Fetch another list of all the jobs loaded into launchd and use as pattern file for grep -f.
  • Filter both lists and find the common elements and print its label along with its path (-A1).
  • Filter via strings to avoid printing binary files.
Luo answered 11/1, 2018 at 21:27 Comment(1)
Note that plists can be loaded into launchctl that aren't in any of those default locations. Steam and 1Password do this. So this won't find everything.Sharynshashlik
L
2

Since launchctl list list PIDs, one method is to use lsof command to see all loaded files of the process, e.g.

launchctl list | grep -o '^[0-9]\+' | xargs -n1 lsof -p | grep plist$

Another way is to run fs_usage command and re-load the .plist file, e.g.

sudo fs_usage | grep -w launchd | grep -w plist
Luo answered 11/1, 2018 at 21:15 Comment(1)
On at least Catalina, the plist is not left open by the launched process, so this solution does not work. Unfortunately. Great idea thoughAutomat
A
0

On Catalina, I devised this script to print out the plist of all regex-matching objects found in the system domain or logged-in users. Please note, this is a BASH script, but also worked in my ZSH test.

Usage: find_loaded_plist [ regex ]

Please report bugs/suggestions in the comments below.

find_loaded_plist() {
     launchctl list  | 
     awk "NR>1 && /${1:-^}/  { print \$3 }"  | 
     while read name; do
             launchctl print system/$name 2>/dev/null | 
                sed -n 's/^[[:space:]]*path = //p'
             for u in $(users |xargs id -u ) ; do                                 
                  launchctl print uid/$u/$name 2>/dev/null |
                     sed -n 's/^[[:space:]]*path = //p'
             done;
     done; 
}
Automat answered 19/3, 2021 at 11:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.