2011-10-11 4 views
9

Tôi cần một cách để truy xuất tất cả các quy trình đang chạy cho tất cả người dùng trên máy Mac (sử dụng Cocoa). Tôi tìm thấy một thực hiện để lấy lại quá trình bằng cách sử dụng sysctl, nhưng tôi cũng cần người dùng đang chạy. Đây là một snipping của những gì tôi đã có để có được danh sách quá trình, nhưng là có một cách để sửa đổi nó để bao gồm người sử dụng là tốt?Tôi có thể sử dụng `sysctl` để lấy danh sách quy trình với người dùng không?

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; 

Trả lời

14

Lưu ý rằng danh sách quá trình được trả về bởi sysctl (3) là một mảng cấu trúc kinfo_proc. Nếu bạn đọc khai báo của kinfo_proc, bạn sẽ thấy rằng nó có một thành viên kp_eproc thuộc kiểu struct eproc, lần lượt có một thành viên e_ucred thuộc kiểu struct _ucred, có thành viên cr_uid kiểu uid_t, đại diện cho id người dùng có hiệu lực của quá trình đó.

Điều này có nghĩa rằng bạn có thể sử dụng chuỗi

.kp_eproc.e_ucred.cr_uid 

để có được id của người sử dụng có hiệu quả. Ví dụ:

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); 
} 

Nếu bạn muốn chuyển đổi id người dùng đến một tên người dùng, bạn có thể sử dụng getpwuid (3) hoặc lõm/thread-safe biến thể của nó, 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); 
} 

Dưới đây là một chương trình mẫu liệt kê tất cả các quy trình với PID tương ứng của họ, uids hiệu quả và tên người dùng tương ứng:

#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

"khai kinfo_proc của , bạn sẽ thấy rằng nó có một thành viên kp_eproc thuộc loại struct eproc, mà lần lượt có một thành viên e_ucred thuộc kiểu struct _ucred, mà lần lượt có một thành viên cr_uid thuộc kiểu uid_t "gotta love indirection in C – Dani

+0

Cảm ơn câu trả lời hay ! – bugfixr

+1

Trên Lion thậm chí sử dụng KERN_PROC_ALL vì mã này không thực hiện trên sysctl không trả về tất cả các quy trình. Mã này trả về 121 trong một thử nghiệm trong khi ps -afx trả về 149. Ngay cả một số quy trình thuộc sở hữu của người dùng đang chạy quá trình sysctl cũng bị bỏ qua. Tôi đã xem xét mã Bavarious một cách cẩn thận và không thể tìm thấy một lỗi liên quan đến chiều dài, ví dụ, mà sẽ được sản xuất sự khác biệt. – ctpenrose