2010-06-10 12 views
27

En primer lugar, sé que se han formulado preguntas similares, pero las respuestas proporcionadas no han sido muy útiles (todas recomiendan una de las siguientes opciones).Recuperar nombres de procesos en ejecución

Tengo una aplicación de usuario que necesita determinar si un proceso en particular se está ejecutando. Esto es lo que sé sobre el proceso:

  • El nombre
  • El usuario (root)
  • Se debe estar ya en funcionamiento, ya que es un LaunchDaemon, lo que significa
  • Su proceso padre debe haber launchd (pid 1)

He intentado varias formas de conseguir esto, pero ninguno ha funcionado hasta ahora. Esto es lo que he intentado:

  1. Correr ps y analizando la salida. Esto funciona, pero es lento (fork/exec es caro), y me gustaría que sea lo más rápido posible.

  2. Utilizando la función GetBSDProcessListlisted here. Esto también funciona, pero la forma en que dicen recuperar el nombre del proceso (accediendo al kp_proc.p_comm de cada estructura kinfo_proc) es defectuosa. El char* resultante sólo contiene los primeros 16 caracteres del nombre del proceso, que se pueden ver en la definición de la kp_proc estructura:

    #define MAXCOMLEN 16 //defined in param.h 
    struct extern_proc { //defined in proc.h 
        ...snip... 
        char p_comm[MAXCOMLEN+1]; 
        ...snip... 
    };
  3. Usando libProc.h para recuperar la información del proceso:

    pid_t pids[1024]; 
    int numberOfProcesses = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0); 
    proc_listpids(PROC_ALL_PIDS, 0, pids, sizeof(pids));  
    for (int i = 0; i < numberOfProcesses; ++i) { 
        if (pids[i] == 0) { continue; } 
        char name[1024]; 
        proc_name(pids[i], name, sizeof(name)); 
        printf("Found process: %s\n", name); 
    }

    Estos trabajos , excepto que tiene el mismo defecto que GetBSDProcessList. Solo se devuelve la primera parte del nombre del proceso.

  4. Utilizando el ProcessManager function en carbono:

    ProcessSerialNumber psn; 
    psn.lowLongOfPSN = kNoProcess; 
    psn.highLongOfPSN = 0; 
    while (GetNextProcess(&psn) == noErr) { 
        CFStringRef procName = NULL; 
        if (CopyProcessName(&psn, &procName) == noErr) { 
        NSLog(@"Found process: %@", (NSString *)procName); 
        } 
        CFRelease(procName); 
    }

    esto no funciona. Solo devuelve un proceso que está registrado con el WindowServer (o algo así). En otras palabras, solo devuelve aplicaciones con UI, y solo para el usuario actual.

  5. No puedo usar -[NSWorkspace launchedApplications], ya que debe ser compatible con 10.5. Además, esto solo devuelve información sobre las aplicaciones que aparecen en el Dock para el usuario actual.

que saben que es posible para recuperar el nombre de los procesos (desde ps puede hacerlo) que se ejecuta, pero la pregunta es "¿Puedo hacerlo sin que se bifurcan y exec'ing ps?".

¿Alguna sugerencia?

EDITAR

Después de hacer muchas más investigaciones, he sido incapaz de encontrar una manera de hacer esto. Encontré this SO question, que se refería a this C file in a python module. Esto fue realmente útil al tratar de usar los valores KERN_PROCARGS en una llamada sysctl.

Sin embargo, el código del módulo Python parecía derivarse de la fuente a ps, which I found here. ps de alguna manera puede obtener la ruta ejecutable de cada proceso en ejecución, pero mis mejores esfuerzos para extraer cómo ha sido infructuoso. Hay una función en print.c llamada getproclline que parece estar haciendo la magia, pero cuando ejecuto el mismo código desde mi propia herramienta de línea de comandos, no puedo recuperar el proceso ejecutable para ningún otro proceso que no sea el mío.

Seguiré experimentando, pero sin pruebas concluyentes, parece que la respuesta de @ drawnonward es la más correcta hasta ahora.


EDITAR (mucho tiempo después)

Gracias a la respuesta pointed to by Quinn Taylor, he encontrado algo que funciona. Obtiene la ruta ejecutable de cada proceso, y luego puedo tomar el último componente de ruta para obtener el nombre del proceso real.

#import <sys/proc_info.h> 
#import <libproc.h> 

int numberOfProcesses = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0); 
pid_t pids[numberOfProcesses]; 
bzero(pids, sizeof(pids)); 
proc_listpids(PROC_ALL_PIDS, 0, pids, sizeof(pids)); 
for (int i = 0; i < numberOfProcesses; ++i) { 
    if (pids[i] == 0) { continue; } 
    char pathBuffer[PROC_PIDPATHINFO_MAXSIZE]; 
    bzero(pathBuffer, PROC_PIDPATHINFO_MAXSIZE); 
    proc_pidpath(pids[i], pathBuffer, sizeof(pathBuffer)); 
    if (strlen(pathBuffer) > 0) { 
     printf("path: %s\n", pathBuffer); 
    } 
} 
+0

Me parece recordar una llamada 'sysctl()' que devuelve una lista completa, aunque los nombres del proceso se truncaron en una cierta longitud. – Wevah

+1

@Wevah eso es correcto. 'sysctl()' devuelve la lista completa, pero los nombres se truncan a 16 caracteres. Ese es el artículo # 2 en la lista. :) –

+0

Ah, no vi 'sysctl()' mencionado (tampoco hice clic en el enlace). (¡Votando la pregunta también, como podría usar esta información!) – Wevah

Respuesta

7

¿Qué le parece esta respuesta a una pregunta relacionada? https://stackoverflow.com/a/12274588/120292 Esto pretende obtener la ruta completa para un proceso por el pid, y puede obtener solo el último componente de ruta.

+0

¡Aún mejor! Gracias, Quinn. –

0

No estoy seguro si esto es lo que está buscando, pero podría utilizar la API de LaunchServices con __ LSCopyApplicationArrayInFrontToBackOrder? He oído hablar de esto, pero nunca lo he usado. Después de buscar en Google, ¿hay una muestra de código que podría proporcionar lo que estás buscando? Realmente no lo sé y estoy adivinando un poco;)

http://gist.github.com/163918

Edición

En realidad, Ha. Aquí hay un puesto de desbordamiento de pila que da esto como una respuesta y enlaces a un mismo puesto que he vinculado a ...

http://www.stackoverflow.com/questions/945033/getting-the-list-of-running-applications-ordered-by-last-use

2

La única lista completa de los procesos en ejecución es proporcionada por 2 anterior, pidiendo al núcleo. Obtener el nombre real del proceso no es sencillo. En pocas palabras, busca el pid en cualquier otra fuente que puedas encontrar hasta que obtengas una coincidencia.

Para algunos procesos, el siguiente trabajo:

ProcessSerialNumber   psn; 
CFStringRef    name = NULL; 
status = GetProcessForPID(inPID , &psn); 
if (noErr == status) CopyProcessName(&psn , &name); 

Para algunos procesos, se puede consultar el pid en los resultados de [[NSWorkspace sharedWorkspace] launchedApplications] por NSApplicationProcessIdentifier. Disponible con 10.2 y posterior. La mayoría, pero tal vez no todos, los elementos en esta lista serán los mismos que CopyProcessName arriba.

Para algunos procesos, puede buscar los argumentos del proceso y obtener la ruta completa desde el primer argumento. Similar a obtener la lista original, pero usando KERN_PROCARGS o KERN_PROCARGS2 como el segundo valor mib. Esto es lo que está haciendo ps.

Para algunos procesos, está atascado con los 16 caracteres p_comm.

+0

+1 ¡esto parece bastante prometedor! Obtener el 'ProcessSerialNumber' no funcionó, pero probaré el enfoque' KERN_PROCARGS' e informaré. –

+0

'KERN_PROCARGS' y' KERN_PROCARGS2' funcionan si mi aplicación también se ejecuta como 'root'. Lamentablemente, no lo es. :( –

+2

Sí, ps es raíz de setuid. Creo que hay un grupo especial, tal vez procmod, que también puede acceder a ellos. Solía ​​haber un conjunto de CPS indocumentado para todo esto, pero parece estar en desuso. Parece que Apple ha convertido esto en un problema de seguridad. – drawnonward

Cuestiones relacionadas