Macos 我可以使用'sysctl'与用户一起检索进程列表吗?

Macos 我可以使用'sysctl'与用户一起检索进程列表吗?,macos,sysctl,Macos,Sysctl,我需要一种方法来检索Mac上所有用户的所有正在运行的进程(使用Cocoa)。我找到了一个使用sysctl检索进程的实现,但我还需要运行的用户。这是我得到流程列表的一个小片段,但是有没有办法修改它以包括用户 int err; kinfo_proc * result; bool done; static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 }; size_t

我需要一种方法来检索Mac上所有用户的所有正在运行的进程(使用Cocoa)。我找到了一个使用sysctl检索进程的实现,但我还需要运行的用户。这是我得到流程列表的一个小片段,但是有没有办法修改它以包括用户

int             err;
kinfo_proc *    result;
bool            done;

static const int    name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
size_t          length;

// a valid pointer procList holder should be passed
assert( procList != NULL );
// But it should not be pre-allocated
assert( *procList == NULL );
// a valid pointer to procCount should be passed
assert( procCount != NULL );

*procCount = 0;

result = NULL;
done = false;

do
{
    assert( result == NULL );

    // Call sysctl with a NULL buffer to get proper length
    length = 0;
    err = sysctl((int *)name,(sizeof(name)/sizeof(*name))-1,NULL,&length,NULL,0);
    if( err == -1 )
        err = errno;

    // Now, proper length is optained
    if( err == 0 )
    {
        result = malloc(length);
        if( result == NULL )
            err = ENOMEM;   // not allocated
    }

    if( err == 0 )
    {
        err = sysctl( (int *)name, (sizeof(name)/sizeof(*name))-1, result, &length, NULL, 0);
        if( err == -1 )
            err = errno;

        if( err == 0 )
            done = true;
        else if( err == ENOMEM )
        {
            assert( result != NULL );
            free( result );
            result = NULL;
            err = 0;
        }
    }
} while ( err == 0 && !done );

// Clean up and establish post condition
if( err != 0 && result != NULL )
{
    free(result);
    result = NULL;
}

*procList = result; // will return the result as procList
if( err == 0 )
    *procCount = length / sizeof( kinfo_proc );

assert( (err == 0) == (*procList != NULL ) );

return err;

请注意,sysctl(3)返回的进程列表是struct kinfo_proc的数组。如果您阅读kinfo_proc的声明,您将看到它有一个struct eproc类型的kp_eproc成员,它又有一个struct ucred类型的e_ucred成员,而struct ucred又有一个uid t类型的cr_uid成员,表示该进程的有效用户id

这意味着您可以使用链

.kp_eproc.e_ucred.cr_uid
获取有效用户的id。例如:

for (int i = 0; i < procCount; i++) {
    printf("pid=%d, uid=%d\n",
        procList[i].kp_proc.p_pid,
        procList[i].kp_eproc.e_ucred.cr_uid);
}
for(int i=0;i
如果要将用户id转换为用户名,可以使用getpwuid(3)或其可重入/线程安全变量getpwuid_r(3):

for(int i=0;ipw_name:“getpwuid()失败”;
printf(“pid=%d,用户=%s\n”,
procList[i].kp_proc.p_pid,
用户名);
}

下面是一个示例程序,它列出了所有进程及其相应的PID、有效UID和相应的用户名:

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <pwd.h>

int main(void) {
    int err = 0;
    struct kinfo_proc *proc_list = NULL;
    size_t length = 0;

    static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };

    // Call sysctl with a NULL buffer to get proper length
    err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1, NULL, &length, NULL, 0);
    if (err) goto ERROR;

    // Allocate buffer
    proc_list = malloc(length);
    if (!proc_list) goto ERROR;

    // Get the actual process list
    err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1, proc_list, &length, NULL, 0);
    if (err) goto ERROR;

    int proc_count = length / sizeof(struct kinfo_proc);

    // use getpwuid_r() if you want to be thread-safe

    for (int i = 0; i < proc_count; i++) {
        uid_t uid = proc_list[i].kp_eproc.e_ucred.cr_uid;
        struct passwd *user = getpwuid(uid);
        char *username = user ? user->pw_name : "user name not found";

        printf("pid=%d, uid=%d, username=%s\n",
                proc_list[i].kp_proc.p_pid,
                uid,
                username);
    }

    free(proc_list);

    return EXIT_SUCCESS;

ERROR:
    perror(NULL);
    free(proc_list);
    return EXIT_FAILURE;
}
#包括
#包括
#包括
#包括
#包括
#包括
内部主(空){
int err=0;
struct kinfo_proc*proc_list=NULL;
尺寸长度=0;
静态常量int name[]={CTL_KERN,KERN_PROC,KERN_PROC_ALL,0};
//使用空缓冲区调用sysctl以获得适当的长度
err=sysctl((int*)name,(sizeof(name)/sizeof(*name))-1,NULL,&长度,NULL,0);
如果(错误)转到错误;
//分配缓冲区
proc_list=malloc(长度);
如果(!proc_list)转到错误;
//获取实际的进程列表
err=sysctl((int*)name,(sizeof(name)/sizeof(*name))-1,proc_list,&length,NULL,0);
如果(错误)转到错误;
int proc_count=长度/大小(结构kinfo_proc);
//如果希望线程安全,请使用getpwuid_r()
对于(int i=0;ipw_name:“未找到用户名”;
printf(“pid=%d,uid=%d,用户名=%s\n”,
进程列表[i].kp\u proc.p\u pid,
uid,
用户名);
}
免费(程序列表);
返回退出成功;
错误:
perror(空);
免费(程序列表);
返回退出失败;
}

“kinfo_proc的声明,你会看到它有一个struct eproc类型的kp_eproc成员,而这又有一个struct ucred类型的e_ucred成员,而这又有一个uid t类型的cr_uid成员”,即使使用KERN_proc_,也会喜欢间接寻址,因为上面的代码sysctl不会返回所有进程。此代码在一次测试中返回121,而ps-afx返回149。甚至运行sysctl进程的用户拥有的某些进程也会被忽略。我仔细查看了Bavariage的代码,没有发现与长度有关的错误,例如,这会产生差异。如何从进程ID获取进程使用的内存?
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <pwd.h>

int main(void) {
    int err = 0;
    struct kinfo_proc *proc_list = NULL;
    size_t length = 0;

    static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };

    // Call sysctl with a NULL buffer to get proper length
    err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1, NULL, &length, NULL, 0);
    if (err) goto ERROR;

    // Allocate buffer
    proc_list = malloc(length);
    if (!proc_list) goto ERROR;

    // Get the actual process list
    err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1, proc_list, &length, NULL, 0);
    if (err) goto ERROR;

    int proc_count = length / sizeof(struct kinfo_proc);

    // use getpwuid_r() if you want to be thread-safe

    for (int i = 0; i < proc_count; i++) {
        uid_t uid = proc_list[i].kp_eproc.e_ucred.cr_uid;
        struct passwd *user = getpwuid(uid);
        char *username = user ? user->pw_name : "user name not found";

        printf("pid=%d, uid=%d, username=%s\n",
                proc_list[i].kp_proc.p_pid,
                uid,
                username);
    }

    free(proc_list);

    return EXIT_SUCCESS;

ERROR:
    perror(NULL);
    free(proc_list);
    return EXIT_FAILURE;
}