7

I'm working on a project where I have a number of PIDs and I have to find out which of these are zombie processes and then kill their parent processes in order to kill the initial zombie process. I am not sure if there is any way to find out what the PPID of a given PID is. Any help would be appreciated.

Husso
  • 262
  • 6
  • 17
  • Possible duplicate of [linux: programmatically get parent pid of another process?](http://stackoverflow.com/questions/1525605/linux-programmatically-get-parent-pid-of-another-process) – Crowman Feb 14 '16 at 23:53
  • There's `get_proc_stats` in `libproc` that would have done what you want. Seems it's been removed from the public interface. The alternative is to use `openproc` and `readproc` to get the pid. I'd post an answer but I cant get it to work myself (crash in `readproc`). I don't know which os you are using so may not apply. Further reading [here](http://stackoverflow.com/questions/6457682/how-to-programatically-get-uid-from-pid-in-osx-using-c), [here](http://goo.gl/W2BBRy) and [here](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=731959). – Paul Rooney Feb 15 '16 at 00:23
  • The best answer is probably dependent on which OSes you are targeting. For Linux, there's the `/proc` filesystem; on BSD, you'll need to call `sysctl()`. I don't know about other systems... – Toby Speight Feb 15 '16 at 10:44

4 Answers4

4

At the source for the ps command, there is a function called get_proc_stats defined in proc/readproc.h that (among other things) returns the parent pid of a given pid. You need to do install libproc-dev to get this function. You can then do:

#include <proc/readproc.h>
void printppid(pid_t pid) {
    proc_t process_info;
    get_proc_stats(pid, &process_info);
    printf("Parent of pid=%d is pid=%d\n", pid, process_info.ppid);
}

This is taken from here. I never used this but according to author this may be helpful.

Shafi
  • 1,850
  • 3
  • 22
  • 44
  • [Get PPid from specific pid in C](https://stackoverflow.com/q/73649093) shows an example of doing it manually, in case anyone's curious. – Peter Cordes Sep 12 '22 at 18:44
2

I've included Linux and macOS/BSD versions using only system libraries.

A pure C using only standard libraries for Linux:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXBUF      (BUFSIZ * 2)

int pgetppid(int pid) {
    int ppid;
    char buf[MAXBUF];
    char procname[32];  // Holds /proc/4294967296/status\0
    FILE *fp;

    snprintf(procname, sizeof(procname), "/proc/%u/status", pid);
    fp = fopen(procname, "r");
    if (fp != NULL) {
        size_t ret = fread(buf, sizeof(char), MAXBUF-1, fp);
        if (!ret) {
            return 0;
        } else {
            buf[ret++] = '\0';  // Terminate it.
        }
    }
    fclose(fp);
    char *ppid_loc = strstr(buf, "\nPPid:");
    if (ppid_loc) {
        ppid = sscanf(ppid_loc, "\nPPid:%d", &ppid);
        if (!ppid || ppid == EOF) {
            return 0;
        }
        return ppid;
    } else {
        return 0;
    }

}

int main () {
    int ppid, pid = 373;  // my current cron pid
    ppid = pgetppid(pid);
    printf("PPid = %d\n", ppid);
}

For macOS and FreeBSD use this:

#include <stdio.h>
#include <sys/sysctl.h>
#include <sys/param.h>
#include <sys/user.h>

int pgetppid(int pid) {

    struct kinfo_proc p;
    size_t len = sizeof(struct kinfo_proc);
    int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid };
    if (sysctl(mib, 4, &p, &len, NULL, 0) < 0)
        return 0;
    if (len == 0)
        return 0;
    int ret;
#if defined(__APPLE__)
        ret = p.kp_eproc.e_ppid; // macOS
    #elif defined(__FreeBSD__)
        ret = p.ki_ppid; // FreeBSD
    #else
        #error "Not supported, try adding an elif for this OS"
    #endif
    return ret;
}

int main () {
    int ppid, pid = 2420;  // my current cron pid
        ppid = pgetppid(pid);
    printf("PPid = %d\n", ppid);
}
James Risner
  • 5,451
  • 11
  • 25
  • 47
0

I found an alternative solution on macOS, inspired by another answer. You can use the undocumented "libproc" methods.

To use libproc in Swift, add the following line to your bridging header:

#import <libproc.h>

Then you can get the ppid using this sample code:

let pid = pid_t(12345)
var shortinfo = proc_bsdshortinfo()
let status = proc_pidinfo(pid, PROC_PIDT_SHORTBSDINFO, 0, &shortinfo, Int32(MemoryLayout.size(ofValue: shortinfo)))
guard status > 0 else {
    let errno_stored = errno
    let errorDescription = String(cString:strerror(errno_stored)!)
    throw NSError(domain: "com.apple.libproc", code: Int(errno_stored), userInfo: [NSLocalizedDescriptionKey: errorDescription])
}
let ppid = pid_t(shortinfo.pbsi_ppid)
Jakob Egger
  • 11,981
  • 4
  • 38
  • 48
-3

The function getppid() does that:

#include <unistd.h>

int main()
{
    pid_t ppid;

    ppid = getppid();

    return (0);
}
ale
  • 6,369
  • 7
  • 55
  • 65
Henry
  • 149
  • 2
  • 8
  • 7
    This will obviously only get the parent pid of the calling process. The OP wants to do this with arbitrary processes, some of which may be zombies, so this doesn't address the question. – Crowman Feb 14 '16 at 23:53
  • Nice peer pressure badge waiting? – James Risner Sep 17 '22 at 13:07