2010-06-10 11 views
27

Prima di tutto, so che domande simili sono state poste, ma le risposte fornite non sono state di grande aiuto finora (raccomandano tutte una delle seguenti opzioni).Recupero nomi di processi in esecuzione

Ho un'applicazione utente che deve determinare se un particolare processo è in esecuzione. Ecco quello che so sul processo:

  • Il nome
  • L'utente (root)
  • E dovrebbe già essere in esecuzione, in quanto si tratta di un LaunchDaemon, il che significa
  • Il suo processo genitore dovrebbe essere launchd (pid 1)

Ho provato diversi modi per ottenere questo, ma nessuno ha funzionato finora. Ecco quello che ho provato:

  1. Esecuzione ps e verificando l'output. Funziona, ma è lento (fork/exec è costoso) e mi piacerebbe che fosse il più veloce possibile.

  2. Utilizzo della funzione listed here. Funziona anche, ma il modo in cui dicono di recuperare il nome del processo (accesso a kp_proc.p_comm da ciascuna struttura kinfo_proc) è difettoso. La risultante char* contiene solo i primi 16 caratteri del nome del processo, che può essere visto nella definizione del kp_proc struttura:

    #define MAXCOMLEN 16 //defined in param.h 
    struct extern_proc { //defined in proc.h 
        ...snip... 
        char p_comm[MAXCOMLEN+1]; 
        ...snip... 
    };
  3. Utilizzando libProc.h per recuperare le informazioni di processo:

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

    questo funziona , tranne che ha lo stesso difetto di GetBSDProcessList. Viene restituita solo la prima parte del nome del processo.

  4. Utilizzando la ProcessManager function in carbonio:

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

    questo non funziona. Restituisce solo i processi registrati con il WindowServer (o qualcosa del genere). In altre parole, restituisce solo app con interfaccia utente e solo per l'utente corrente.

  5. Non riesco a utilizzare -[NSWorkspace launchedApplications], poiché questo deve essere compatibile con 10.5. Inoltre, questo restituisce solo le informazioni sulle applicazioni visualizzate nel Dock per l'utente corrente.

So che è possibile per recuperare il nome dei processi in esecuzione (poiché ps può farlo), ma la domanda è: "Posso farlo senza sborsare e exec'ing ps?".

Qualche suggerimento?

EDIT

Dopo aver fatto una ricerca molto di più, sono stato in grado di trovare un modo per farlo. Ho trovato this SO question, che si riferiva a this C file in a python module. Ciò è stato davvero utile nel tentativo di utilizzare i valori KERN_PROCARGS in una chiamata sysctl.

Tuttavia, il codice del modulo Python sembrava essere derivato dalla sorgente a ps, which I found here. ps può in qualche modo ottenere il percorso eseguibile di ogni processo in esecuzione, ma i miei migliori sforzi per estrarre lo in modo che lo facesse non hanno avuto successo. C'è una funzione in print.c chiamata getproclline che sembra stia facendo la magia, ma quando eseguo lo stesso codice dal mio strumento da riga di comando, non riesco a recuperare l'eseguibile del processo per processi diversi dal mio.

Continuerò a sperimentare, ma senza prove più conclusive, sembra che la risposta di @ drawnonward sia la più corretta finora.


EDIT (molto tempo dopo)

Grazie alla risposta pointed to by Quinn Taylor, ho trovato qualcosa che funziona. Ottiene il percorso dell'eseguibile di ogni processo e quindi posso semplicemente prendere l'ultimo componente del percorso per ottenere il nome del processo effettivo.

#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

Mi sembra di ricordare una chiamata 'sysctl() che restituisce un elenco completo, sebbene i nomi dei processi siano stati troncati di una certa lunghezza. – Wevah

+1

@Wevah è corretto. 'sysctl()' restituisce l'elenco completo, ma i nomi vengono troncati a 16 caratteri. Questo è l'articolo n. 2 nella lista. :) –

+0

Ah, non ho visto 'sysctl()' menzionato (inoltre non ho fatto clic sul collegamento). (Anche votando la domanda, potrei usare queste informazioni!) – Wevah

risposta

7

Che dire di questa risposta a una domanda correlata? https://stackoverflow.com/a/12274588/120292 Questo pretende di ottenere il percorso completo per un processo dal pid, e si può prendere solo l'ultimo componente del percorso.

+0

Ancora meglio! Grazie, Quinn. –

0

Non so se questo è quello che stai cercando, ma potresti utilizzare l'API con LaunchServices __ LSCopyApplicationArrayInFrontToBackOrder? Ne ho sentito parlare, ma non l'ho mai usato da solo. Dopo qualche ricerca su google, ecco un esempio di codice che potrebbe fornire quello che stai cercando? Io davvero non lo so e sto faccia un po ';)

http://gist.github.com/163918

Modifica

In realtà, Ha. Ecco un post Stack Overflow che dà a questo come una risposta e collegamenti con lo stesso posto ho collegato a ...

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

2

L'unica lista completa dei processi in esecuzione è fornita da 2 di cui sopra, chiedendo al kernel. Ottenere il vero nome del processo non è semplice. In poche parole, si guarda il pid in qualsiasi altra fonte che si possa trovare fino a quando non si ottiene una corrispondenza.

Per alcuni processi, il seguente funziona:

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

Per alcuni processi, è possibile cercare il pid nei risultati di [[NSWorkspace sharedWorkspace] launchedApplications] da NSApplicationProcessIdentifier. Disponibile con 10.2 e versioni successive. La maggior parte, ma forse non tutti, gli elementi in questo elenco saranno gli stessi di CopyProcessName di cui sopra.

Per alcuni processi, è possibile cercare gli argomenti del processo e ottenere il percorso completo dal primo argomento. Simile all'ottenere l'elenco originale, ma utilizzando KERN_PROCARGS o KERN_PROCARGS2 come secondo valore di mib. Questo è ciò che sta facendo ps.

Per alcuni processi, sei bloccato con il carattere di 16 p_comm.

+0

+1 sembra abbastanza promettente! Ottenere il 'ProcessSerialNumber' non ha funzionato, ma proverò l'approccio' KERN_PROCARGS' e riferirò. –

+0

'KERN_PROCARGS' e' KERN_PROCARGS2' funzionano se la mia app funziona anche come 'root'. Sfortunatamente, non lo è. :( –

+2

Sì, ps è setuid root.Penso che ci sia un gruppo speciale, forse procmod, che può anche accedervi.Una volta era una suite CPS priva di documenti per questa roba, ma sembra essere deprecata. ha reso questo un problema di sicurezza – drawnonward

Problemi correlati