KCMP - Linux手册页

时间:2019-08-20 17:58:55  来源:igfitidea点击:

Linux程序员手册 第2部分
更新日期: 2020-06-09

名称

kcmp-比较两个进程以确定它们是否共享内核资源

语法

#include <linux/kcmp.h>

int kcmp(pid_t pid1, pid_t pid2, int type,
         unsigned long idx1, unsigned long idx2);

注意:此系统调用没有glibc包装器。请参阅注释。

说明

kcmp()系统调用可用于检查pid1和pid2标识的两个进程是否共享内核资源,例如虚拟内存,文件描述符等。

使用kcmp()的权限由ptrace访问模式PTRACE_MODE_READ_REALCREDS对pid1和pid2进行检查来控制;参见ptrace(2)。

类型参数指定在两个进程中要比较的资源。它具有以下值之一:

KCMP_FILE
检查进程pid1中的文件描述符idx1是否引用与进程pid2中的文件描述符idx2相同的打开文件描述(请参阅open(2))。 dup(2)(和类似的结果)fork(2)或通过域套接字传递文件描述符(参见unix(7))的结果可能是存在两个引用同一打开文件描述的文件描述符。
KCMP_FILES
检查进程是否共享同一组打开文件描述符。参数idx1和idx2被忽略。请参阅对clone(2)中的CLONE_FILES标志的讨论。
KCMP_FS
检查进程是否共享相同的文件系统信息(即文件模式创建掩码,工作目录和文件系统根目录)。参数idx1和idx2被忽略。请参阅对clone(2)中的CLONE_FS标志的讨论。
KCMP_IO
检查进程是否共享I / O上下文。参数idx1和idx2被忽略。请参阅对clone(2)中CLONE_IO标志的讨论。
KCMP_SIGHAND
检查进程是否共享相同的信号处理表。参数idx1和idx2被忽略。请参阅对clone(2)中的CLONE_SIGHAND标志的讨论。
KCMP_SYSVSEM
检查进程是否共享相同的System V信号量撤消操作列表。参数idx1和idx2被忽略。请参阅对clone(2)中的CLONE_SYSVSEM标志的讨论。
KCMP_VM
检查进程是否共享相同的地址空间。参数idx1和idx2被忽略。请参阅对clone(2)中的CLONE_VM标志的讨论。
KCMP_EPOLL_TFD(since Linux 4.13)
检查进程pid2的idx2描述的epoll(7)实例中是否存在进程pid1的文件描述符idx1。参数idx2是指向描述目标文件的结构的指针。该结构的形式为:
struct kcmp_epoll_slot {
    __u32 efd;
    __u32 tfd;
    __u64 toff;
};

在此结构中,efd是从epoll_create(2)返回的epoll文件描述符,tfd是目标文件描述符编号,并且toff是从零开始计数的目标文件偏移量。可以使用相同的文件描述符编号注册多个不同的目标,并且设置特定的偏移量有助于调查每个目标。

请注意,如果进程当前正在运行,则不会保护kcmp()免受误报。在通过此系统调用进行检查之前,应通过发送SIGSTOP(请参见signal(7))来停止进程,以获得有意义的结果。

返回值

成功调用kcmp()的返回值只是内核指针的算术比较的结果(当内核比较资源时,它将使用其内存地址)。

解释的最简单方法是考虑一个例子。假设v1和v2是适当资源的地址,则返回值为以下之一:

0
v1等于v2;换句话说,两个进程共享资源。
1
v1小于v2。
2
v1大于v2。
3
v1不等于v2,但是订购信息不可用。

如果出错,则返回-1,并正确设置errno。

kcmp()设计为返回适合排序的值。如果需要比较大量的文件描述符,这特别方便。

错误说明

EBADF
类型为KCMP_FILE,并且fd1或fd2不是打开的文件描述符。
EFAULT
由idx2寻址的epoll插槽在用户地址空间之外。
EINVAL
类型无效。
ENOENT
目标文件在epoll(7)实例中不存在。
EPERM
权限不足,无法检查流程资源。需要CAP_SYS_PTRACE功能才能检查您不拥有的进程。其他ptrace限制也可能适用,例如CONFIG_SECURITY_YAMA,当/ proc / sys / kernel / yama / ptrace_scope为2时,它将kcmp()限制到子进程;参见ptrace(2)。
ESRCH
进程pid1或pid2不存在。

版本

kcmp()系统调用首先出现在Linux 3.5中。

遵循规范

kcmp()是特定于Linux的,不应在旨在可移植的程序中使用。

备注

Glibc不为该系统调用提供包装器;使用syscall(2)调用它。

仅当内核配置了CONFIG_CHECKPOINT_RESTORE时,此系统调用才可用。系统调用的主要用途是用于用户空间中的检查点/还原(CRIU)功能。该系统调用的替代方法是通过proc(5)文件系统公开合适的过程信息;出于安全原因,这被认为是不合适的。

有关此页面上引用的共享资源的一些背景信息,请参见clone(2)。

示例

下面的程序使用kcmp()测试文件描述符对是否引用相同的打开文件描述。程序将测试文件描述符对的不同情况,如程序输出中所述。该程序的示例运行如下:

$ ./a.out
Parent PID is 1144
Parent opened file on FD 3

PID of child of fork() is 1145
        Compare duplicate FDs from different processes:
                kcmp(1145, 1144, KCMP_FILE, 3, 3) ==> same
Child opened file on FD 4
        Compare FDs from distinct open()s in same process:
                kcmp(1145, 1145, KCMP_FILE, 3, 4) ==> different
Child duplicated FD 3 to create FD 5
        Compare duplicated FDs in same process:
                kcmp(1145, 1145, KCMP_FILE, 3, 5) ==> same

Program source

#define _GNU_SOURCE
#include <sys/syscall.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/kcmp.h>

#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                        } while (0)

static int
kcmp(pid_t pid1, pid_t pid2, int type,
     unsigned long idx1, unsigned long idx2)
{
    return syscall(SYS_kcmp, pid1, pid2, type, idx1, idx2);
}

static void
test_kcmp(char *msg, id_t pid1, pid_t pid2, int fd_a, int fd_b)
{
    printf("\t%s\n", msg);
    printf("\t\tkcmp(%ld, %ld, KCMP_FILE, %d, %d) ==> %s\n",
            (long) pid1, (long) pid2, fd_a, fd_b,
            (kcmp(pid1, pid2, KCMP_FILE, fd_a, fd_b) == 0) ?
                        "same" : "different");
}

int
main(int argc, char *argv[])
{
    int fd1, fd2, fd3;
    char pathname[] = "/tmp/kcmp.test";

    fd1 = open(pathname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
    if (fd1 == -1)
        errExit("open");

    printf("Parent PID is %ld\n", (long) getpid());
    printf("Parent opened file on FD %d\n\n", fd1);

    switch (fork()) {
    case -1:
        errExit("fork");

    case 0:
        printf("PID of child of fork() is %ld\n", (long) getpid());

        test_kcmp("Compare duplicate FDs from different processes:",
                getpid(), getppid(), fd1, fd1);

        fd2 = open(pathname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
        if (fd2 == -1)
            errExit("open");
        printf("Child opened file on FD %d\n", fd2);

        test_kcmp("Compare FDs from distinct open()s in same process:",
                getpid(), getpid(), fd1, fd2);

        fd3 = dup(fd1);
        if (fd3 == -1)
            errExit("dup");
        printf("Child duplicated FD %d to create FD %d\n", fd1, fd3);

        test_kcmp("Compare duplicated FDs in same process:",
                getpid(), getpid(), fd1, fd3);
        break;

    default:
        wait(NULL);
    }

    exit(EXIT_SUCCESS);
}

另外参见

克隆(2),取消共享(2)

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/