2011-10-11 35 views
9

我需要一種方法來檢索Mac上所有用戶的所有正在運行的進程(使用Cocoa)。我發現一個實現使用sysctl檢索進程,但我也需要運行用戶。這是我得到進程列表的剪輯,但是有沒有辦法修改它以包含用戶呢?我可以使用`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; 

回答

14

請注意,sysctl(3)返回的進程列表是struct kinfo_proc的數組。如果你讀了kinfo_proc的聲明,你會看到它有一個類型爲struct eproc的kp_eproc成員,它具有一個類型爲struct _ucred的e_ucred成員,而該成員又具有一個類型爲uid_t的cr_uid成員,它代表該過程。

這意味着你可以使用鏈

.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; 
} 
+0

「kinfo_proc增加的聲明,你會發現它有一個類型爲struct eproc的kp_eproc成員,該成員又有一個類型爲struct _ucred的e_ucred成員,而該成員又具有一個類型爲uid_t的cr_uid成員「在C – Dani

+0

中獲得了愛情間接感謝感謝您的好回答! – bugfixr

+1

在Lion上,即使使用KERN_PROC_ALL作爲此代碼,上面的sysctl也不會返回所有進程。此代碼在一次測試中返回121,而ps -afx返回149.即使運行sysctl進程的用戶擁有的某些進程也會被忽略。我仔細研究了Bavarious的代碼,並且找不到長度方面的錯誤,例如,這會產生差異。 – ctpenrose

相關問題