2010-06-10 4 views
27

Во-первых, я знаю, что схожие вопросы были заданы, но предоставленные ответы пока не очень помогли (все они рекомендуют один из следующих вариантов).Извлечь имена запущенных процессов

У меня есть пользовательское приложение, которое должно определить, работает ли какой-либо конкретный процесс. Вот что я знаю о процессе:

  • Имя
  • Пользователь (root)
  • Он должен уже запущен, так как это LaunchDaemon, что означает
  • его родительский процесс должен быть launchd (pid 1)

Я пробовал несколько способов получить это, но до сих пор никто не работал. Вот что я пытался:

  1. Запуск ps и анализа вывода. Это работает, но оно медленное (fork/exec дорого), и я хотел бы, чтобы это было как можно быстрее.

  2. Использование функции GetBSDProcessListlisted here. Это также работает, но способ, которым они говорят, чтобы получить имя процесса (доступ к kp_proc.p_comm от каждой структуры kinfo_proc) является ошибочным. В результате char* содержит только первые 16 символов имени процесса, которые можно увидеть в определении kp_proc структуры:

    #define MAXCOMLEN 16 //defined in param.h 
    struct extern_proc { //defined in proc.h 
        ...snip... 
        char p_comm[MAXCOMLEN+1]; 
        ...snip... 
    };
  3. Использование libProc.h для получения информации о процессе:

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

    это работает , за исключением того, что он имеет тот же недостаток, что и GetBSDProcessList. Возвращается только первая часть имени процесса.

  4. Использование ProcessManager function в Carbon:

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

    Это не работает. Он возвращает процесс, зарегистрированный в WindowServer (или что-то в этом роде). Другими словами, он только возвращает приложения с пользовательскими интерфейсами и только для текущего пользователя.

  5. Я не могу использовать -[NSWorkspace launchedApplications], так как это должно быть 10,5-совместимым. Кроме того, это только возвращает информацию о приложениях, которые отображаются в Dock для текущего пользователя.

Я знаю, что это возможного получить имя запущенных процессов (так как ps может сделать это), но вопрос «Могу ли я сделать это без разветвления и exec'ing ps?».

Любые предложения?

EDIT

После этого намного больше исследований, я не смог найти способ сделать это. Я нашел this SO question, который ссылался на this C file in a python module. Это было действительно полезно при попытке использовать значения KERN_PROCARGS в вызове sysctl.

Однако код модуля Python, по-видимому, был получен от источника до ps, which I found here. ps может каким-то образом получить исполняемый путь каждого работающего процесса, но все мои усилия, чтобы извлечь , как, его выполнение было безуспешным. Есть функция в print.c, которая называется getproclline, которая, кажется, выполняет магию, но когда я запускаю один и тот же код из своего собственного инструмента командной строки, я не могу получить исполняемый файл процесса для любых процессов, отличных от моих собственных.

Я буду продолжать экспериментировать, но без каких-либо убедительных доказательств, похоже, что ответ на вопрос, который был приведен на прошлой неделе, является наиболее правильным.


EDIT (долгое время спустя)

Благодаря ответу pointed to by Quinn Taylor, я нашел то, что работает. Он получает исполняемый путь каждого процесса, а затем я могу просто захватить последний компонент пути, чтобы получить фактическое имя процесса.

#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

Кажется, что я вызываю вызов 'sysctl()', который возвращает полный список, хотя имена процессов были усечены на определенной длине. – Wevah

+1

@Wevah это правильно. 'sysctl()' возвращает полный список, но имена усекаются до 16 символов. Это элемент №2 в списке. :) –

+0

Ах, я не видел 'sysctl()' упомянутый (я также не нажимал ссылку). (Голосование вопрос тоже, как я мог бы использовать эту информацию!) – Wevah

ответ

7

Как насчет ответа на соответствующий вопрос? https://stackoverflow.com/a/12274588/120292 Это подразумевает получение полного пути для процесса pid, и вы можете захватить только последний компонент пути.

+0

Еще лучше! Спасибо, Куинн. –

0

Не уверен, если это то, что вы ищете, но вы могли бы использовать LaunchServices API с __ LSCopyApplicationArrayInFrontToBackOrder? Я слышал об этом, но никогда не использовал его сам. После некоторого googling, вот образец кода, который может предоставить то, что вы ищете? Я действительно не знаю, и я немного угадывания;)

http://gist.github.com/163918

Редактировать

На самом деле, Ха. Вот сообщение о переполнении стека, что дает это как ответ и ссылки на тот же пост я связан с ...

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

2

Единственный полный список запущенных процессов обеспечиваются 2 выше, попросив ядро. Получение фактического имени процесса не является прямым. В двух словах, вы смотрите pid в любом другом источнике, который вы можете найти, пока не получите совпадение.

Для некоторых процессов, следующий будет работать:

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

Для некоторых процессов, вы можете посмотреть ИДП в результатах [[NSWorkspace sharedWorkspace] launchedApplications] по NSApplicationProcessIdentifier. Доступно с 10.2 и более поздними версиями. Большинство, но, возможно, не все, элементы в этом списке будут такими же, как и CopyProcessName выше.

Для некоторых процессов вы можете найти аргументы процесса и получить полный путь от первого аргумента. Аналогично получению исходного списка, но с использованием KERN_PROCARGS или KERN_PROCARGS2 в качестве второго значения mib. Это то, что делает ps.

Для некоторых процессов вы застреваете с 16 символами p_comm.

+0

+1 это выглядит довольно многообещающе! Получение «ProcessSerialNumber» не сработало, но я попробую «KERN_PROCARGS» и отчитаюсь. –

+0

'KERN_PROCARGS' и' KERN_PROCARGS2' работают, если мое приложение также работает как 'root'. К сожалению, это не так. :( –

+2

Да, ps - это setuid root. Я думаю, что есть специальная группа, возможно, procmod, которая также может получить к ним доступ. Для этого был всего недокументированный CPS-пакет, но, похоже, он устарел. сделал это проблемой безопасности. – drawnonward