如何监控其使用C PID活动的外部进程? [英] How to monitor an external process for events by its PID in C?

查看:127
本文介绍了如何监控其使用C PID活动的外部进程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有这得到了一些功能允许一个监视事态外部进程任何图书馆的将为pid_t ?我的意思是,监控外部进程是否已经退出,或者是否已经创建了一个或多个子进程(与),或者它是否已经成为另一个可执行映像(通过 EXEC 的posix_spawn 函数调用族)或Unix的信号是否被传递给它。

Is there any library which's got some function the allows one to monitor an external process for events by its pid_t? I mean, monitor whether an external process has exited, or whether it has created one or more child processes (with fork), or whether it has become another executable image (via an exec or posix_spawn function family call) or whether a Unix signal was delivered to it.

修改

我需要的东西不与正被监视的程序的执行干扰。所以,我不应该,因为它停止时,它会发出一些信号,被监视的过程中使用 ptrace的,并恢复过程中,每当出现这种情况是必要的。

I need something that does not interfere with the execution of the program that is being monitored. So, I'm not supposed to use ptrace, since it stops the process which is being monitored when it emits some signal and it's necessary to resume the process whenever this happens.

推荐答案

运行使用捕捉叉preLOAD库中的目标二进制文件()。只要所有的子进程还使用了preLOAD库,你会看到所有的本地的子进程,无论怎样执行。

Run the target binary using a preload library that catches fork(). As long as all child processes also use the preload library, you'll see all local child processes, no matter how executed.

下面是一个例子的实现。

Here is an example implementation.

首先, forkmonitor.h 头文件。它定义了从preLOAD库传递的消息,对监测过程:

First, the forkmonitor.h header file. It defines the messages passed from the preload library, to the monitoring process:

#ifndef   FORKMONITOR_H
#define   FORKMONITOR_H

#define   FORKMONITOR_ENVNAME "FORKMONITOR_SOCKET"

#ifndef   UNIX_PATH_MAX
#define   UNIX_PATH_MAX 108
#endif

#define TYPE_EXEC       1   /* When a binary is executed */
#define TYPE_DONE       2   /* exit() or return from main() */
#define TYPE_FORK       3
#define TYPE_VFORK      4
#define TYPE_EXIT       5   /* _exit() or _Exit() */
#define TYPE_ABORT      6   /* abort() */

struct message {
    pid_t          pid;     /* Process ID */
    pid_t          ppid;    /* Parent process ID */
    pid_t          sid;     /* Session ID */
    pid_t          pgid;    /* Process group ID */
    uid_t          uid;     /* Real user ID */
    gid_t          gid;     /* Real group ID */
    uid_t          euid;    /* Effective user ID */
    gid_t          egid;    /* Effective group ID */
    unsigned short len;     /* Length of data[] */
    unsigned char  type;    /* One of the TYPE_ constants */
    char           data[0]; /* Optional payload, possibly longer */
};

#endif /* FORKMONITOR_H */

FORKMONITOR_SOCKET 环境变量(由名为 FORKMONITOR_ENVNAME 上面的宏)指定Unix域数据报套接字addess到监测过程。如果没有定义或空的,没有监控消息发送。

The FORKMONITOR_SOCKET environment variable (named by the FORKMONITOR_ENVNAME macro above) specifies the Unix domain datagram socket addess to the monitoring process. If not defined or empty, no monitoring messages are sent.

下面是库​​本身, libforkmonitor.c
请注意,我简化了code颇有几分,离开了多线程的初始化(因为它是罕见的库调用任何的拦截功能,甚至是罕见的,从多个线程做)。这将是更好地使用原子的内置插件(__sync_bool_compare_and_swap())来更新函数指针和原子吸气剂(__sync_fetch_and_or(0))来获取函数指针,以避免与靠不住库中的任何问题。 (这是一个多线程程序相当安全,因为指针只会之前修改的main()执行。)

Here is the library itself, libforkmonitor.c. Note that I simplified the code quite a bit, leaving out multithreaded initialization (since it's rare for a library to call any of the intercepted functions, and even rarer to do it from multiple threads). It would be better to use atomic built-ins (__sync_bool_compare_and_swap()) to update the function pointer, and atomic getter (__sync_fetch_and_or(,0)) to retrieve the function pointer, to avoid any issues with wonky libraries. (This is quite safe for multithreaded programs, as the pointers will only be modified prior to main() is executed.)

#define  _POSIX_C_SOURCE 200809L
#define  _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <dlfcn.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include "forkmonitor.h"

static pid_t (*actual_fork)(void)  = NULL;
static pid_t (*actual_vfork)(void) = NULL;
static void  (*actual_abort)(void) = NULL;
static void  (*actual__exit)(int)  = NULL;
static void  (*actual__Exit)(int)  = NULL;
static int     commfd = -1;

#define MINIMUM_COMMFD  31

static void notify(const int type, struct message *const msg, const size_t extra)
{
    const int    saved_errno = errno;

    msg->pid  = getpid();
    msg->ppid = getppid();
    msg->sid  = getsid(0);
    msg->pgid = getpgrp();
    msg->uid  = getuid();
    msg->gid  = getgid();
    msg->euid = geteuid();
    msg->egid = getegid();
    msg->len  = extra;
    msg->type = type;

    /* Since we don't have any method of dealing with send() errors
     * or partial send()s, we just fire one off and hope for the best. */
    send(commfd, msg, sizeof (struct message) + extra, MSG_EOR | MSG_NOSIGNAL);

    errno = saved_errno;
}

void libforkmonitor_init(void) __attribute__((constructor));
void libforkmonitor_init(void)
{
    const int saved_errno = errno;
    int       result;

    /* Save the actual fork() call pointer. */
    if (!actual_fork)
        *(void **)&actual_fork = dlsym(RTLD_NEXT, "fork");

    /* Save the actual vfork() call pointer. */
    if (!actual_vfork)
        *(void **)&actual_vfork = dlsym(RTLD_NEXT, "vfork");

    /* Save the actual abort() call pointer. */
    if (!actual_abort)
        *(void **)&actual_abort = dlsym(RTLD_NEXT, "abort");

    /* Save the actual _exit() call pointer. */
    if (!actual__exit)
        *(void **)&actual__exit = dlsym(RTLD_NEXT, "_exit");
    if (!actual__exit)
        *(void **)&actual__exit = dlsym(RTLD_NEXT, "_Exit");

    /* Save the actual abort() call pointer. */
    if (!actual__Exit)
        *(void **)&actual__Exit = dlsym(RTLD_NEXT, "_Exit");
    if (!actual__Exit)
        *(void **)&actual__Exit = dlsym(RTLD_NEXT, "_exit");

    /* Open an Unix domain datagram socket to the observer. */
    if (commfd == -1) {
        const char *address;

        /* Connect to where? */
        address = getenv(FORKMONITOR_ENVNAME);
        if (address && *address) {
            struct sockaddr_un addr;

            memset(&addr, 0, sizeof addr);
            addr.sun_family = AF_UNIX;
            strncpy(addr.sun_path, address, sizeof addr.sun_path - 1);

            /* Create and bind the socket. */
            commfd = socket(AF_UNIX, SOCK_DGRAM, 0);
            if (commfd != -1) {
                if (connect(commfd, (const struct sockaddr *)&addr, sizeof (addr)) == -1) {
                    /* Failed. Close the socket. */
                    do {
                        result = close(commfd);
                    } while (result == -1 && errno == EINTR);
                    commfd = -1;
                }
            }

            /* Move commfd to a high descriptor, to avoid complications. */
            if (commfd != -1 && commfd < MINIMUM_COMMFD) {
                const int newfd = MINIMUM_COMMFD;
                do {
                    result = dup2(commfd, newfd);
                } while (result == -1 && errno == EINTR);
                if (!result) {
                    do {
                        result = close(commfd);
                    } while (result == -1 && errno == EINTR);
                    commfd = newfd;
                }
            }
        }
    }

    /* Send an init message, listing the executable path. */
    if (commfd != -1) {
        size_t          len = 128;
        struct message *msg = NULL;

        while (1) {
            ssize_t n;

            free(msg);
            msg = malloc(sizeof (struct message) + len);
            if (!msg) {
                len = 0;
                break;
            }

            n = readlink("/proc/self/exe", msg->data, len);
            if (n > (ssize_t)0 && (size_t)n < len) {
                msg->data[n] = '\0';
                len = n + 1;
                break;
            }

            len = (3 * len) / 2;
            if (len >= 65536U) {
                free(msg);
                msg = NULL;
                len = 0;
                break;
            }
        }

        if (len > 0) {
            /* INIT message with executable name */
            notify(TYPE_EXEC, msg, len);
            free(msg);
        } else {
            /* INIT message without executable name */
            struct message msg2;
            notify(TYPE_EXEC, &msg2, sizeof msg2);
        }
    }

    /* Restore errno. */
    errno = saved_errno;
}

void libforkmonitor_done(void) __attribute__((destructor));
void libforkmonitor_done(void)
{
    const int saved_errno = errno;
    int       result;

    /* Send an exit message, no data. */
    if (commfd != -1) {
        struct message msg;
        notify(TYPE_DONE, &msg, sizeof msg);
    }

    /* If commfd is open, close it. */
    if (commfd != -1) {
        do {
            result = close(commfd);
        } while (result == -1 && errno == EINTR);
    }

    /* Restore errno. */
    errno = saved_errno;
}

/*
 * Hooked C library functions.
*/

pid_t fork(void)
{
    pid_t result;

    if (!actual_fork) {
        const int saved_errno = errno;

        *(void **)&actual_fork = dlsym(RTLD_NEXT, "fork");
        if (!actual_fork) {
            errno = EAGAIN;
            return (pid_t)-1;
        }

        errno = saved_errno;
    }

    result = actual_fork();
    if (!result && commfd != -1) {
        struct message msg;
        notify(TYPE_FORK, &msg, sizeof msg);
    }

    return result;
}

pid_t vfork(void)
{
    pid_t result;

    if (!actual_vfork) {
        const int saved_errno = errno;

        *(void **)&actual_vfork = dlsym(RTLD_NEXT, "vfork");
        if (!actual_vfork) {
            errno = EAGAIN;
            return (pid_t)-1;
        }

        errno = saved_errno;
    }

    result = actual_vfork();
    if (!result && commfd != -1) {
        struct message msg;
        notify(TYPE_VFORK, &msg, sizeof msg);
    }

    return result;
}

void _exit(const int code)
{
    if (!actual__exit) {
        const int saved_errno = errno;
        *(void **)&actual__exit = dlsym(RTLD_NEXT, "_exit");
        if (!actual__exit)
            *(void **)&actual__exit = dlsym(RTLD_NEXT, "_Exit");
        errno = saved_errno;
    }

    if (commfd != -1) {
        struct {
            struct message  msg;
            int             extra;
        } data;

        memcpy(&data.msg.data[0], &code, sizeof code);
        notify(TYPE_EXIT, &(data.msg), sizeof (struct message) + sizeof (int));
    }

    if (actual__exit)
        actual__exit(code);

    exit(code);
}

void _Exit(const int code)
{
    if (!actual__Exit) {
        const int saved_errno = errno;
        *(void **)&actual__Exit = dlsym(RTLD_NEXT, "_Exit");
        if (!actual__Exit)
            *(void **)&actual__Exit = dlsym(RTLD_NEXT, "_exit");
        errno = saved_errno;
    }

    if (commfd != -1) {
        struct {
            struct message  msg;
            int             extra;
        } data;

        memcpy(&data.msg.data[0], &code, sizeof code);
        notify(TYPE_EXIT, &(data.msg), sizeof (struct message) + sizeof (int));
    }

    if (actual__Exit)
        actual__Exit(code);

    exit(code);
}

void abort(void)
{
    if (!actual_abort) {
        const int saved_errno = errno;
        *(void **)&actual_abort = dlsym(RTLD_NEXT, "abort");
        errno = saved_errno;
    }

    if (commfd != -1) {
        struct message msg;
        notify(TYPE_ABORT, &msg, sizeof msg);
    }

    actual_abort();
    exit(127);
}

libforkmonitor_init()功能自动运行时链接过程之前名为的main()被调用,和 libforkmonitor_done()被调用时从过程返回的main()或呼叫退出( )

The libforkmonitor_init() function is called automatically by the runtime linker before the process main() is called, and libforkmonitor_done() is called when the process returns from main() or calls exit().

libforkmonitor_init()打开一个Unix域数据报套接字的监测过程,并立即将其凭据和路径当前的可执行文件。每个子进程(只要preLOAD库仍然加载),它们加载后执行这一点,所以没有必要赶 EXEC *()的posix_spawn *()或'popen()完成`等等功能都没有。

The libforkmonitor_init() opens an Unix domain datagram socket to the monitoring process, and sends its credentials and the path to the current executable. Every child process (as long as the preload library is still loaded) executes this after they're loaded, so there is no need to catch exec*() or posix_spawn*() or 'popen()` etc. functions at all.

C库函数叉()的vfork()被截获。需要这些拦截赶情况下,原来的程序叉不执行任何其他二进制创建从属进程。 (至少GNU C库使用叉()内部,所以这会赶上的popen()的posix_spawn()等了。)

The C library functions fork() and vfork() are intercepted. These interceptions are needed to catch the cases where the original program forks to create slave processes without executing any other binary. (At least GNU C library uses fork() internally, so these will catch popen(), posix_spawn(), etc. too.)

此外,C库函数 _exit() _Exit()中止()被截获了。我说这些,因为一些二进制文件,尤其是短跑,喜欢用 _exit(),而且我认为这将是很好的捕捉所有形式的出口正常的。 (未检测到人由于信号,然而,;而如果一个二进制执行另一个二进制,你只会得到新的消息EXEC注进程,父进程ID的)

Additionally, C library functions _exit(), _Exit(), and abort() are intercepted too. I added these because some binaries, especially Dash, like to use _exit(), and I thought it would be nice to catch all forms of normal exits. (Death due to signals is not detected, however; and if a binary executes another binary, you'll only get the new EXEC message. Note the process and parent process ID's.)

下面是一个简单的监控程序, forkmonitor.c

Here is a simple monitoring program, forkmonitor.c:

#define  _POSIX_C_SOURCE 200809L
#include <unistd.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
#include <pwd.h>
#include <grp.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include "forkmonitor.h"

static volatile sig_atomic_t  done = 0;

static void done_handler(const int signum)
{
    if (!done)
        done = signum;
}

static int catch_done(const int signum)
{
    struct sigaction  act;

    sigemptyset(&act.sa_mask);
    act.sa_handler = done_handler;
    act.sa_flags = 0;

    if (sigaction(signum, &act, NULL) == -1)
        return errno;

    return 0;
}

static const char *username(const uid_t uid)
{
    static char    buffer[128];
    struct passwd *pw;

    pw = getpwuid(uid);
    if (!pw)
        return NULL;

    strncpy(buffer, pw->pw_name, sizeof buffer - 1);
    buffer[sizeof buffer - 1] = '\0';

    return (const char *)buffer;
}

static const char *groupname(const gid_t gid)
{
    static char   buffer[128];
    struct group *gr;

    gr = getgrgid(gid);
    if (!gr)
        return NULL;

    strncpy(buffer, gr->gr_name, sizeof buffer - 1);
    buffer[sizeof buffer - 1] = '\0';

    return (const char *)buffer;
}

int main(int argc, char *argv[])
{
    const size_t    msglen = 65536;
    struct message *msg;
    int             socketfd, result;
    const char     *user, *group;

    if (catch_done(SIGINT) || catch_done(SIGQUIT) || catch_done(SIGHUP) ||
        catch_done(SIGTERM) || catch_done(SIGPIPE)) {
        fprintf(stderr, "Cannot set signal handlers: %s.\n", strerror(errno));
        return 1;
    }

    if (argc != 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
        fprintf(stderr, "\n");
        fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
        fprintf(stderr, "       %s MONITOR-SOCKET-PATH\n", argv[0]);
        fprintf(stderr, "\n");
        fprintf(stderr, "This program outputs events reported by libforkmonitor\n");
        fprintf(stderr, "to Unix domain datagram sockets at MONITOR-SOCKET-PATH.\n");
        fprintf(stderr, "\n");
        return 0;
    }

    msg = malloc(msglen);
    if (!msg) {
        fprintf(stderr, "Out of memory.\n");
        return 1;
    }

    socketfd = socket(AF_UNIX, SOCK_DGRAM, 0);
    if (socketfd == -1) {
        fprintf(stderr, "Cannot create an Unix domain datagram socket: %s.\n", strerror(errno));
        return 1;
    }

    {
        struct sockaddr_un  addr;
        size_t              len;

        if (argv[1])
            len = strlen(argv[1]);
        else
            len = 0;
        if (len < 1 || len >= UNIX_PATH_MAX) {
            fprintf(stderr, "%s: Path is too long (max. %d characters)\n", argv[1], UNIX_PATH_MAX - 1);
            return 1;
        }

        memset(&addr, 0, sizeof addr);
        addr.sun_family = AF_UNIX;
        memcpy(addr.sun_path, argv[1], len + 1); /* Include '\0' at end */

        if (bind(socketfd, (struct sockaddr *)&addr, sizeof (addr)) == -1) {
            fprintf(stderr, "Cannot bind to %s: %s.\n", argv[1], strerror(errno));
            return 1;
        }
    }

    printf("Waiting for connections.\n");
    printf("\n");

    /* Infinite loop. */
    while (!done) {
        ssize_t  n;

        n = recv(socketfd, msg, msglen, 0);
        if (n == -1) {
            const char *const errmsg = strerror(errno);
            fprintf(stderr, "%s.\n", errmsg);
            fflush(stderr);
            break;
        }

        if (msglen < sizeof (struct message)) {
            fprintf(stderr, "Received a partial message; discarded.\n");
            fflush(stderr);
            continue;
        }

        switch (msg->type) {
        case TYPE_EXEC:
            printf("Received an EXEC message:\n");
            break;
        case TYPE_DONE:
            printf("Received a DONE message:\n");
            break;
        case TYPE_FORK:
            printf("Received a FORK message:\n");
            break;
        case TYPE_VFORK:
            printf("Received a VFORK message:\n");
            break;
        case TYPE_EXIT:
            printf("Received an EXIT message:\n");
            break;
        case TYPE_ABORT:
            printf("Received an ABORT message:\n");
            break;
        default:
            printf("Received an UNKNOWN message:\n");
            break;
        }

        if (msg->type == TYPE_EXEC && (size_t)n > sizeof (struct message)) {
            if (*((char *)msg + n - 1) == '\0')
                printf("\tExecutable:        '%s'\n", (char *)msg + sizeof (struct message));
        }

        printf("\tProcess ID:         %d\n", (int)msg->pid);
        printf("\tParent process ID:  %d\n", (int)msg->ppid);
        printf("\tSession ID:         %d\n", (int)msg->sid);
        printf("\tProcess group ID:   %d\n", (int)msg->pgid);

        user = username(msg->uid);
        if (user)
            printf("\tReal user:         '%s' (%d)\n", user, (int)msg->uid);
        else
            printf("\tReal user:          %d\n", (int)msg->uid);

        group = groupname(msg->gid);
        if (group)
            printf("\tReal group:        '%s' (%d)\n", group, (int)msg->gid);
        else
            printf("\tReal group:         %d\n", (int)msg->gid);

        user = username(msg->euid);
        if (user)
            printf("\tEffective user:    '%s' (%d)\n", user, (int)msg->euid);
        else
            printf("\tEffective user:     %d\n", (int)msg->euid);

        group = groupname(msg->egid);
        if (group)
            printf("\tEffective group:   '%s' (%d)\n", group, (int)msg->egid);
        else
            printf("\tEffective group:    %d\n", (int)msg->egid);

        printf("\n");
        fflush(stdout);
    }

    do {
        result = close(socketfd);
    } while (result == -1 && errno == EINTR);

    unlink(argv[1]);

    return 0;
}

这需要一个命令行参数,Unix域套接字地址。它应该是一个绝对的文件系统路径。

It takes a single command-line parameter, the Unix domain socket address. It should be an absolute file system path.

您可以通过 INT 停止监视程序(<大骨节病>按Ctrl + C ), HUP 退出 TERM 信号。

You can stop the monitoring program via INT (Ctrl+C), HUP, QUIT, and TERM signals.

使用编译库

gcc -W -Wall -O3 -fpic -fPIC -c libforkmonitor.c
gcc -shared -Wl,-soname,libforkmonitor.so libforkmonitor.o -ldl -o libforkmonitor.so

和使用监控程序

gcc -W -Wall -O3 forkmonitor.c -o forkmonitor

在一个终端窗口中,首先启动forkmonitor:

In one terminal window, start the forkmonitor first:

./forkmonitor "$PWD/commsocket"

在另一个终端窗口,在同一目录下,运行监控命令,自动preloading的 libforkmonitor.so 库,并指定监视器的插座:

In another terminal window, in the same directory, run the monitored command, automatically preloading the libforkmonitor.so library and specifying the socket for the monitor:

env "LD_PRELOAD=$PWD/libforkmonitor.so" "FORKMONITOR_SOCKET=$PWD/commsocket" command args...

请注意,由于这里使用了 LD_ preLOAD FORKMONITOR_SOCKET 环境变量,子进程,如果忽略执行的setuid 的setgid 二进制文件时,他们的父母修改环境(去掉两个环境变量)和。可通过消除环境变量,和硬编码它们可以避免这种限制。

Note that because this uses the LD_PRELOAD and FORKMONITOR_SOCKET environment variables, child processes are ignored if their parent modifies the environment (removing the two environment variables), and when executing setuid or setgid binaries. This limitation can be avoided by eliminating the environment variables, and hardcoding them.

运行时链接器不会preLOAD库的setuid 的setgid 可执行文件,除非库在标准库目录之一,也标志着的setgid

The run-time linker will not preload libraries for setuid or setgid binaries, unless the library is in one of the standard library directories, and also marked setgid.

添加库名称 /etc/ld.so.$p$pload 将preLOAD库中的所有可执行文件,但你可能应该添加一个机制到 libforkmonitor_init()这限制了监控所需的二进制文件和/或指定的实际用户(如运行setuid二进制命令有效时,用户更改)。

Adding the library name to /etc/ld.so.preload will preload the library for all binaries, but you probably should add a mechanism into libforkmonitor_init() which limits the monitoring to desired binaries and/or a specified real user (as effective user changes when running a setuid binary).

例如,当我运行

env "LD_PRELOAD=$PWD/libforkmonitor.so" "FORKMONITOR_SOCKET=$PWD/commsocket" sh -c 'date ; ls -laF'

监控输出(匿名):

the monitoring output is (anonymized):

Received an EXEC message:
Executable:        'bin/dash'
Process ID:         11403
Parent process ID:  9265
Session ID:         9265
Process group ID:   11403
Real user:         'username' (1000)
Real group:        'username' (1000)
Effective user:    'username' (1000)
Effective group:   'username' (1000)

Received a FORK message:
Process ID:         11404
Parent process ID:  11403
Session ID:         9265
Process group ID:   11403
Real user:         'username' (1000)
Real group:        'username' (1000)
Effective user:    'username' (1000)
Effective group:   'username' (1000)

Received an EXEC message:
Executable:        'bin/date'
Process ID:         11404
Parent process ID:  11403
Session ID:         9265
Process group ID:   11403
Real user:         'username' (1000)
Real group:        'username' (1000)
Effective user:    'username' (1000)
Effective group:   'username' (1000)

Received a DONE message:
Process ID:         11404
Parent process ID:  11403
Session ID:         9265
Process group ID:   11403
Real user:         'username' (1000)
Real group:        'username' (1000)
Effective user:    'username' (1000)
Effective group:   'username' (1000)

Received a FORK message:
Process ID:         11405
Parent process ID:  11403
Session ID:         9265
Process group ID:   11403
Real user:         'username' (1000)
Real group:        'username' (1000)
Effective user:    'username' (1000)
Effective group:   'username' (1000)

Received an EXEC message:
Executable:        'bin/ls'
Process ID:         11405
Parent process ID:  11403
Session ID:         9265
Process group ID:   11403
Real user:         'username' (1000)
Real group:        'username' (1000)
Effective user:    'username' (1000)
Effective group:   'username' (1000)

Received a DONE message:
Process ID:         11405
Parent process ID:  11403
Session ID:         9265
Process group ID:   11403
Real user:         'username' (1000)
Real group:        'username' (1000)
Effective user:    'username' (1000)
Effective group:   'username' (1000)

Received an EXIT message:
Process ID:         11403
Parent process ID:  9265
Session ID:         9265
Process group ID:   11403
Real user:         'username' (1000)
Real group:        'username' (1000)
Effective user:    'username' (1000)
Effective group:   'username' (1000)

这是一个非常轻量级进程树监控解决方案。除了进程启动,退出,并调用的拦截功能之一(叉()的vfork() _exit() _Exit()中止())时,程序执行根本不会受到影响。因为图书馆是如此轻巧,甚至影响只能由一个非常,非常少量的受影响者;可能没有足够可靠地测量。

This is a very lightweight process tree monitoring solution. Other than process startup, exit, and calling one of the intercepted functions (fork(), vfork(), _exit(), _Exit(), abort()), program execution will not be affected at all. Because the library is so lightweight, even those affected will only be affected by a very, very small amount; probably not enough to measure reliably.

这显然可以拦截等功能,和/或使用双向通信,暂停的拦截功能的执行,直到监视应用程序的响应。

It is obviously possible to intercept other functions, and/or use two-way communication, "pausing" the execution of the intercepted function until the monitoring application responds.

有一些缺陷的整体,特别是有关的setuid / setgid的流程,以及流程,生成一个新的环境(省略 LD_ preLOAD FORKMONITOR_SOCKET 环境变量),但是如果超级用户权限,可那些可以被周围的工作。

There are some pitfalls overall, especially related to setuid/setgid processes, and processes that generate a new environment (omitting the LD_PRELOAD and FORKMONITOR_SOCKET environment variables), but those can be worked around if superuser privileges are available.

希望你能找到这个信息。有问题?

Hope you find this informative. Questions?

这篇关于如何监控其使用C PID活动的外部进程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆