Home > Net >  finding absolute path name of a process on macOS
finding absolute path name of a process on macOS

Time:08-25

I am new in GO and mac, and I'm trying to use sysctl for finding the full path name of running processes.

kprocs, err := unix.SysctlKinfoProcSlice("kern.proc.all")
    if err != nil {
        fmt.Println("error: ", err)
    }

    for _, proc := range kprocs {
        name := string(proc.Proc.P_comm[:])
        pid := proc.Proc.P_pid
        extName, err := unix.SysctlKinfoProc("kern.proc.pathname", int(pid))
        if err != nil {
            fmt.Println("error: ", err)
        }

and getting error: no such file or directory

am I using this function correcly?

EDIT If I run the process like this: ./processName ,then I am not getting it's full path, for example /Users/username/go/src/processName - which is what I need. All the solutions with ps will give the relative path, and I need someting that gives the absolute path of the process.

CodePudding user response:

Here you go:

func printPath(pid int32) {
    cmd := exec.Command("ps", append([]string{"xuwww", "-p", strconv.Itoa(int(pid))})...)
    output, e := cmd.CombinedOutput()
    if e != nil {
        fmt.Println(e)
    }
    lines := strings.Split(string(output), "\n")
    comps := strings.Fields(lines[1])

    fmt.Println(comps[len(comps)-1])
}

func main() {
    kprocs, err := unix.SysctlKinfoProcSlice("kern.proc.all")
    if err != nil {
        fmt.Println("error: ", err)
    }

    for _, proc := range kprocs {
        pid := proc.Proc.P_pid
        printPath(pid)
    }
}

I didn't use unix.SysctlKinfoProc(), instead ran a shell command ps xuwww -p PID using exec.command(). It returns output as string. Parse the output string to get absolute path.

Output:

649 /System/Library/PrivateFrameworks/IMDPersistence.framework/XPCServices/IMDPersistenceAgent.xpc/Contents/MacOS/IMDPersistenceAgent 646 /System/Library/PrivateFrameworks/AuthKit.framework/Versions/A/Support/akd 643 /System/Library/CoreServices/pbs

CodePudding user response:

Following my comment on your question you can get the information you are looking for by using lsof.

Similar to the other code example you can iterate over all known processes but for some processes it takes some time for the command to return.

package main

import (
    "fmt"
    "os/exec"

    "golang.org/x/sys/unix"
)

func printPath(pid int32) {
    cmd := exec.Command("bash", "-c", fmt.Sprintf("lsof -p %d -Fn | awk 'NR==5{print}' | sed \"s/n\\//\\//\"", pid))
    output, e := cmd.CombinedOutput()
    if e != nil {
        fmt.Println(e)
        return
    }
    fmt.Printf("%s", output)
}

func main() {
    kprocs, err := unix.SysctlKinfoProcSlice("kern.proc.all")
    if err != nil {
        fmt.Println("error: ", err)
    }

    for _, proc := range kprocs {
        pid := proc.Proc.P_pid
        fmt.Printf("getting for pid %d: ", pid)
        printPath(pid)
    }
}

The code output can be improved. Processes that have exited already now make the output kind of a mess :-/

  • Related