2011-10-11 5 views
9

Necesito una forma de recuperar todos los procesos en ejecución para todos los usuarios en una Mac (usando Cocoa). Encontré una implementación para recuperar el proceso usando sysctl, pero también necesito el usuario en ejecución. Esto es un recorte de lo que tengo que obtener de la lista de procesos, pero ¿hay alguna forma de modificarlo para incluir también al usuario?¿Puedo usar `sysctl` para recuperar una lista de procesos con el usuario?

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; 

Respuesta

14

Tenga en cuenta que la lista de procesos devuelta por sysctl (3) es una matriz de struct kinfo_proc. Si lee la declaración de kinfo_proc, verá que tiene un miembro kp_eproc de tipo struct eproc, que a su vez tiene un miembro e_ucred de tipo struct _ucred, que a su vez tiene un miembro cr_uid del tipo uid_t, que representa el ID de usuario efectivo de ese proceso.

Esto significa que se puede utilizar la cadena

.kp_eproc.e_ucred.cr_uid 

obtener el ID del usuario eficaz. Por ejemplo:

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

Si desea convertir el identificador de usuario a un nombre de usuario, puede utilizar getpwuid (3) o su reentrada 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); 
} 

Aquí está un ejemplo de programa que enumera todos los procesos con sus correspondientes PID, fluidos eficaces y nombres de usuario correspondientes:

#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

"declaración de kinfo_proc , verás que tiene un miembro kp_eproc de tipo struct eproc, que a su vez tiene un miembro e_ucred de tipo struct _ucred, que a su vez tiene un miembro cr_uid de tipo uid_t "gotta love indirection in C – Dani

+0

Gracias por la buena respuesta ! – bugfixr

+1

En Lion incluso usando KERN_PROC_ALL como este código hace arriba de sysctl no devuelve todos los procesos. Este código devuelve 121 en una prueba mientras que ps -afx devuelve 149. Incluso se ignoran algunos procesos que pertenecen al usuario que ejecuta el proceso sysctl. He observado el código de Bavarious con cuidado y no puedo encontrar un error con respecto a la longitud, por ejemplo, que estaría produciendo la discrepancia. – ctpenrose

Cuestiones relacionadas