2011-10-11 4 views
9

Ho bisogno di un modo per recuperare tutti i processi in esecuzione per tutti gli utenti su un Mac (usando Cocoa). Ho trovato un'implementazione per recuperare il processo usando sysctl, ma ho anche bisogno di un utente in esecuzione. Questo è un taglio di ciò che ho avuto per ottenere l'elenco dei processi, ma c'è un modo per modificarlo per includere anche l'utente?Posso usare `sysctl` per recuperare un elenco di processi con l'utente?

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; 

risposta

14

noti che l'elenco processo restituito da sysctl (3) è un array di struct kinfo_proc. Se leggi la dichiarazione di kinfo_proc, vedrai che ha un membro kp_eproc di tipo struct eproc, che a sua volta ha un membro e_ucred di tipo struct_ucred, che a sua volta ha un membro cr_uid di tipo uid_t, che rappresenta l'id utente effettivo di quel processo.

Questo significa che è possibile utilizzare la catena

.kp_eproc.e_ucred.cr_uid 

per ottenere l'id utente effettivo. Per esempio:

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

Se si desidera convertire l'ID utente per un nome utente, è possibile utilizzare getpwuid (3) o la sua rientrante/variante thread-safe, 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); 
} 

Ecco un esempio di programma che elenca tutti i processi con i loro corrispondenti PID, UID efficaci ei nomi degli utenti corrispondenti:

#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

"dichiarazione di kinfo_proc vedrai che ha un membro kp_eproc di tipo struct eproc, che a sua volta ha un membro e_ucred di tipo struct_ucred, che a sua volta ha un membro cr_uid di tipo uid_t "devi amore indiretto in C – Dani

+0

Grazie per la bella risposta ! – bugfixr

+1

Su Lion anche usando KERN_PROC_ALL come questo codice fa sopra sysctl non restituisce tutti i processi. Questo codice restituisce 121 in un test mentre ps -afx restituisce 149. Anche alcuni processi di proprietà dell'utente che esegue il processo sysctl vengono ignorati. Ho guardato attentamente il codice di Bavarious e non sono riuscito a trovare un bug riguardo alla lunghezza, ad esempio, che avrebbe prodotto la discrepanza. – ctpenrose

Problemi correlati