我可以使用 `sysctl` 来检索用户的进程列表吗?
Posted
技术标签:
【中文标题】我可以使用 `sysctl` 来检索用户的进程列表吗?【英文标题】:Can I use `sysctl` to retrieve a process list with the user? 【发布时间】:2011-12-05 11:12:37 【问题描述】:我需要一种方法来检索 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】:请注意,sysctl(3) 返回的进程列表是一个 struct kinfo_proc 数组。如果你阅读 kinfo_proc 的声明,你会看到它有一个 struct eproc 类型的 kp_eproc 成员,它又具有一个 struct _ucred 类型的 e_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);
如果要将用户 id 转换为用户名,可以使用 getpwuid(3) 或其可重入/线程安全的变体 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);
这是一个示例程序,列出了所有进程及其对应的 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;
【讨论】:
"kinfo_proc 的声明,你会看到它有一个 struct eproc 类型的 kp_eproc 成员,它又具有一个 struct _ucred 类型的 e_ucred 成员,而后者又具有一个 uid_t 类型的 cr_uid 成员"必须喜欢 C 中的间接寻址 在 Lion 上,即使使用 KERN_PROC_ALL 就像这段代码在 sysctl 上所做的那样,也不会返回所有进程。此代码在一次测试中返回 121,而 ps -afx 返回 149。甚至运行 sysctl 进程的用户拥有的某些进程也会被忽略。我仔细查看了 Bavarious 的代码,并没有找到一个关于长度的错误,例如,这会产生差异。 如何获取进程使用的内存表单有进程ID?以上是关于我可以使用 `sysctl` 来检索用户的进程列表吗?的主要内容,如果未能解决你的问题,请参考以下文章
在 iOS 上调用 sysctl 来获取后台进程列表是私人电话吗?
使用 sysctl() 的每个进程的 iOS cpu 使用情况?
是否有任何 C 函数或 API 来获取在当前登录用户下运行的进程列表