我可以使用“sysctl”來檢索用戶的進程列表嗎?

[英]Can I use `sysctl` to retrieve a process list with the user?


I am in need of a way to retrieve all running processes for all users on a Mac (using Cocoa). I found an implementation to retrieve the process using sysctl, but I also need the running user. This is a snipping of what I've got to get the process list, but is there a way to modify it to include the user as well?

我需要一種方法來檢索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;

1 个解决方案

#1


14  

Note that the process list returned by sysctl(3) is an array of struct kinfo_proc. If you read kinfo_proc’s declaration, you’ll see that it has a kp_eproc member of type struct eproc, which in turn has an e_ucred member of type struct _ucred, which in turn has a cr_uid member of type uid_t, representing the effective user id of that process.

注意,sysctl(3)返回的進程列表是一個struct kinfo_proc數組。如果您閱讀kinfo_proc的聲明,您將看到它有一個類型為struct eproc的kp_eproc成員,它反過來又有一個類型為struct _ucred的e_ucred成員,它又有一個類型為uid_t的cr_uid成員,表示該進程的有效用戶id。

This means that you can use the chain

這意味着你可以使用鏈。

.kp_eproc.e_ucred.cr_uid

to obtain the id of the effective user. For example:

獲取有效用戶的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);
}

If you want to convert the user id to a user name, you can use getpwuid(3) or its reentrant/thread-safe variant, getpwuid_r(3):

如果要將用戶id轉換為用戶名,可以使用getpwuid(3)或它的reentrant/線程安全變體getpwuid_r(3):

for (int i = 0; i < procCount; i++) {
    struct passwd *user = getpwuid(procList[i].kp_eproc.e_ucred.cr_uid);
    char *username = user ? user->pw_name : "getpwuid() failed";
    printf("pid=%d, user=%s\n",
        procList[i].kp_proc.p_pid,
        username);
}

Here’s a sample program that lists all processes with their corresponding pids, effective uids and corresponding usernames:

下面是一個示例程序,它列出了所有進程及其相應的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;
}

注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2011/10/11/7205e5bb1e949ae884337a9c7788cf3b.html



 
粤ICP备14056181号  © 2014-2020 ITdaan.com