给定一个子进程ID,如何获取其父进程ID

7

我正在处理一个项目,其中有许多PID,我需要找出哪些是僵尸进程,然后杀死它们的父进程以杀死最初的僵尸进程。我不确定是否有任何方法可以找出给定PID的PPID是什么。如果有帮助,请告诉我。


libproc中有一个名为get_proc_stats的函数可以实现你想要的功能。但似乎已经从公共接口中删除了。替代方法是使用openprocreadproc来获取pid。我会回答,但我自己无法使其工作(在readproc中崩溃)。我不知道您使用的操作系统,因此可能不适用。更多阅读这里这里这里 - Paul Rooney
最佳答案可能取决于您的目标操作系统。对于Linux,有/proc文件系统;在BSD上,则需要调用sysctl()函数。至于其他系统,我不是很清楚... - Toby Speight
4个回答

4

在ps命令的源代码中,有一个名为get_proc_stats的函数,在proc/readproc.h中定义,它(除其他功能外)返回给定pid的父进程pid。你需要安装libproc-dev来获取该函数。然后可以执行以下操作:

#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);
}

这段内容摘自这里。 我从未使用过,但据作者说可能会有帮助。

Get PPid from specific pid in C展示了一个手动获取PPid的例子,以防有人感兴趣。 - Peter Cordes

2

我已经包含了仅使用系统库的Linux和macOS/BSD版本。

一个纯C仅使用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);
}

对于macOS和FreeBSD,请使用以下内容:

#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);
}

0

我在 macOS 上找到了一种替代方案,受到另一个答案的启发。您可以使用未记录的“libproc”方法。

要在 Swift 中使用 libproc,请将以下行添加到您的桥接标头中:

#import <libproc.h>

然后您可以使用此示例代码获取ppid:

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)

-3

函数 getppid() 这样做:

#include <unistd.h>

int main()
{
    pid_t ppid;

    ppid = getppid();

    return (0);
}

7
这显然只能获取调用进程的父进程pid。而原帖作者想对任意进程执行此操作,其中有些进程可能是僵尸进程,因此这并没有解决问题。 - Crowman
漂亮的同行压力徽章等待中? - James Risner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接